OLD | NEW |
---|---|
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 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 "content/renderer/media/webrtc/video_destination_handler.h" | 5 #include "content/renderer/media/webrtc/video_destination_handler.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 | 8 |
9 #include "base/base64.h" | 9 #include "base/base64.h" |
10 #include "base/debug/trace_event.h" | 10 #include "base/debug/trace_event.h" |
(...skipping 23 matching lines...) Expand all Loading... | |
34 // Starts forwarding frames to |frame_callback| on the IO-thread that are | 34 // Starts forwarding frames to |frame_callback| on the IO-thread that are |
35 // delivered to this class by calling DeliverFrame on the main render thread. | 35 // delivered to this class by calling DeliverFrame on the main render thread. |
36 void StartDeliver(const VideoCaptureDeliverFrameCB& frame_callback); | 36 void StartDeliver(const VideoCaptureDeliverFrameCB& frame_callback); |
37 void StopDeliver(); | 37 void StopDeliver(); |
38 | 38 |
39 void DeliverFrame(const scoped_refptr<PPB_ImageData_Impl>& image_data, | 39 void DeliverFrame(const scoped_refptr<PPB_ImageData_Impl>& image_data, |
40 int64 time_stamp_ns); | 40 int64 time_stamp_ns); |
41 | 41 |
42 private: | 42 private: |
43 friend class base::RefCountedThreadSafe<FrameWriterDelegate>; | 43 friend class base::RefCountedThreadSafe<FrameWriterDelegate>; |
44 enum PixelEndian { | |
45 UNKNOWN, | |
46 AXXX, | |
47 XXXA, | |
48 }; | |
49 | |
44 virtual ~FrameWriterDelegate(); | 50 virtual ~FrameWriterDelegate(); |
45 | 51 |
46 void StartDeliverOnIO(const VideoCaptureDeliverFrameCB& frame_callback); | 52 void StartDeliverOnIO(const VideoCaptureDeliverFrameCB& frame_callback); |
47 void StopDeliverOnIO(); | 53 void StopDeliverOnIO(); |
48 | 54 |
49 void DeliverFrameOnIO(uint8* data, int stride, int width, int height, | 55 void DeliverFrameOnIO(uint8* data, int stride, int width, int height, |
50 int64 time_stamp_ns); | 56 int64 time_stamp_ns); |
51 void FrameDelivered(const scoped_refptr<PPB_ImageData_Impl>& image_data); | 57 void FrameDelivered(const scoped_refptr<PPB_ImageData_Impl>& image_data); |
52 | 58 |
53 scoped_refptr<base::MessageLoopProxy> io_message_loop_; | 59 scoped_refptr<base::MessageLoopProxy> io_message_loop_; |
54 | 60 |
55 // |frame_pool_| and |new_frame_callback_| are only used on the IO-thread. | 61 // |frame_pool_|, |new_frame_callback_| and |endian_| are only used on the |
62 // IO-thread. | |
56 media::VideoFramePool frame_pool_; | 63 media::VideoFramePool frame_pool_; |
57 VideoCaptureDeliverFrameCB new_frame_callback_; | 64 VideoCaptureDeliverFrameCB new_frame_callback_; |
65 PixelEndian endian_; | |
58 | 66 |
59 // Used to DCHECK that we are called on the main render thread. | 67 // Used to DCHECK that we are called on the main render thread. |
60 base::ThreadChecker thread_checker_; | 68 base::ThreadChecker thread_checker_; |
61 }; | 69 }; |
62 | 70 |
63 PpFrameWriter::FrameWriterDelegate::FrameWriterDelegate( | 71 PpFrameWriter::FrameWriterDelegate::FrameWriterDelegate( |
64 const scoped_refptr<base::MessageLoopProxy>& io_message_loop_proxy) | 72 const scoped_refptr<base::MessageLoopProxy>& io_message_loop_proxy) |
65 : io_message_loop_(io_message_loop_proxy) { | 73 : io_message_loop_(io_message_loop_proxy), endian_(UNKNOWN) { |
66 } | 74 } |
67 | 75 |
68 PpFrameWriter::FrameWriterDelegate::~FrameWriterDelegate() { | 76 PpFrameWriter::FrameWriterDelegate::~FrameWriterDelegate() { |
69 } | 77 } |
70 | 78 |
71 void PpFrameWriter::FrameWriterDelegate::StartDeliver( | 79 void PpFrameWriter::FrameWriterDelegate::StartDeliver( |
72 const VideoCaptureDeliverFrameCB& frame_callback) { | 80 const VideoCaptureDeliverFrameCB& frame_callback) { |
73 DCHECK(thread_checker_.CalledOnValidThread()); | 81 DCHECK(thread_checker_.CalledOnValidThread()); |
74 io_message_loop_->PostTask( | 82 io_message_loop_->PostTask( |
75 FROM_HERE, | 83 FROM_HERE, |
(...skipping 18 matching lines...) Expand all Loading... | |
94 << "The image could not be mapped and is unusable."; | 102 << "The image could not be mapped and is unusable."; |
95 return; | 103 return; |
96 } | 104 } |
97 | 105 |
98 const SkBitmap* bitmap = image_data->GetMappedBitmap(); | 106 const SkBitmap* bitmap = image_data->GetMappedBitmap(); |
99 if (!bitmap) { | 107 if (!bitmap) { |
100 LOG(ERROR) << "PpFrameWriter::PutFrame - " | 108 LOG(ERROR) << "PpFrameWriter::PutFrame - " |
101 << "The image_data's mapped bitmap is NULL."; | 109 << "The image_data's mapped bitmap is NULL."; |
102 return; | 110 return; |
103 } | 111 } |
112 // We only support PP_IMAGEDATAFORMAT_BGRA_PREMUL at the moment. | |
113 DCHECK(image_data->format() == PP_IMAGEDATAFORMAT_BGRA_PREMUL); | |
104 io_message_loop_->PostTaskAndReply( | 114 io_message_loop_->PostTaskAndReply( |
105 FROM_HERE, | 115 FROM_HERE, |
106 base::Bind(&FrameWriterDelegate::DeliverFrameOnIO, this, | 116 base::Bind(&FrameWriterDelegate::DeliverFrameOnIO, this, |
107 static_cast<uint8*>(bitmap->getPixels()), | 117 static_cast<uint8*>(bitmap->getPixels()), |
108 bitmap->rowBytes(), | 118 bitmap->rowBytes(), |
109 bitmap->width(), | 119 bitmap->width(), |
110 bitmap->height(), | 120 bitmap->height(), |
111 time_stamp_ns), | 121 time_stamp_ns), |
112 base::Bind(&FrameWriterDelegate::FrameDelivered, this, | 122 base::Bind(&FrameWriterDelegate::FrameDelivered, this, |
113 image_data)); | 123 image_data)); |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
146 // WebRtcVideoCapturerAdapter before the frame is delivered to libJingle. | 156 // WebRtcVideoCapturerAdapter before the frame is delivered to libJingle. |
147 // crbug/359587. | 157 // crbug/359587. |
148 scoped_refptr<media::VideoFrame> new_frame = | 158 scoped_refptr<media::VideoFrame> new_frame = |
149 frame_pool_.CreateFrame(media::VideoFrame::YV12, frame_size, | 159 frame_pool_.CreateFrame(media::VideoFrame::YV12, frame_size, |
150 gfx::Rect(frame_size), frame_size, timestamp); | 160 gfx::Rect(frame_size), frame_size, timestamp); |
151 media::VideoCaptureFormat format( | 161 media::VideoCaptureFormat format( |
152 frame_size, | 162 frame_size, |
153 MediaStreamVideoSource::kUnknownFrameRate, | 163 MediaStreamVideoSource::kUnknownFrameRate, |
154 media::PIXEL_FORMAT_YV12); | 164 media::PIXEL_FORMAT_YV12); |
155 | 165 |
156 libyuv::BGRAToI420(data, | 166 // TODO(magjed): Remove this and always use libyuv::ARGBToI420 when |
157 stride, | 167 // crbug/426020 is fixed. |
158 new_frame->data(media::VideoFrame::kYPlane), | 168 // Due to confusion about endianness, we try to determine it from the data. |
159 new_frame->stride(media::VideoFrame::kYPlane), | 169 // The alpha channel is always 255. It is unlikely for other color channels to |
160 new_frame->data(media::VideoFrame::kUPlane), | 170 // be 255, so we will most likely break on the first few pixels in the first |
161 new_frame->stride(media::VideoFrame::kUPlane), | 171 // frame. |
162 new_frame->data(media::VideoFrame::kVPlane), | 172 uint8* row_ptr = data; |
163 new_frame->stride(media::VideoFrame::kVPlane), | 173 for (int y = 0; y < height && endian_ == UNKNOWN; ++y) { |
164 frame_size.width(), frame_size.height()); | 174 for (int x = 0; x < width; ++x) { |
175 if (row_ptr[x * 4 + 0] != 255) { | |
176 endian_ = XXXA; | |
177 break; | |
178 } | |
179 if (row_ptr[x * 4 + 3] != 255) { | |
180 endian_ = AXXX; | |
181 break; | |
182 } | |
183 } | |
184 row_ptr += stride; | |
185 } | |
186 if (endian_ == UNKNOWN) { | |
187 LOG(WARNING) << "PpFrameWriter::FrameWriterDelegate::DeliverFrameOnIO - " | |
188 << "Could not determine endianness."; | |
189 } | |
190 const auto xxxxToI420 = | |
191 (endian_ == AXXX) ? libyuv::BGRAToI420 : libyuv::ARGBToI420; | |
brucedawson
2014/10/22 17:58:41
This reads very strangely. If endian_ is AXXX then
magjed_chromium
2014/10/22 18:18:14
I agree that it looks strange, but AXXX/XXXA is in
| |
192 xxxxToI420(data, | |
193 stride, | |
194 new_frame->data(media::VideoFrame::kYPlane), | |
195 new_frame->stride(media::VideoFrame::kYPlane), | |
196 new_frame->data(media::VideoFrame::kUPlane), | |
197 new_frame->stride(media::VideoFrame::kUPlane), | |
198 new_frame->data(media::VideoFrame::kVPlane), | |
199 new_frame->stride(media::VideoFrame::kVPlane), | |
200 width, | |
201 height); | |
165 | 202 |
166 // The local time when this frame is generated is unknown so give a null | 203 // The local time when this frame is generated is unknown so give a null |
167 // value to |estimated_capture_time|. | 204 // value to |estimated_capture_time|. |
168 new_frame_callback_.Run(new_frame, format, base::TimeTicks()); | 205 new_frame_callback_.Run(new_frame, format, base::TimeTicks()); |
169 } | 206 } |
170 | 207 |
171 PpFrameWriter::PpFrameWriter() { | 208 PpFrameWriter::PpFrameWriter() { |
172 DVLOG(3) << "PpFrameWriter ctor"; | 209 DVLOG(3) << "PpFrameWriter ctor"; |
173 delegate_ = new FrameWriterDelegate(io_message_loop()); | 210 delegate_ = new FrameWriterDelegate(io_message_loop()); |
174 } | 211 } |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
253 bool track_enabled = true; | 290 bool track_enabled = true; |
254 | 291 |
255 stream.addTrack(MediaStreamVideoTrack::CreateVideoTrack( | 292 stream.addTrack(MediaStreamVideoTrack::CreateVideoTrack( |
256 writer, constraints, MediaStreamVideoSource::ConstraintsCallback(), | 293 writer, constraints, MediaStreamVideoSource::ConstraintsCallback(), |
257 track_enabled)); | 294 track_enabled)); |
258 | 295 |
259 return true; | 296 return true; |
260 } | 297 } |
261 | 298 |
262 } // namespace content | 299 } // namespace content |
OLD | NEW |