Index: content/renderer/media/webrtc/video_destination_handler.cc |
diff --git a/content/renderer/media/webrtc/video_destination_handler.cc b/content/renderer/media/webrtc/video_destination_handler.cc |
index 160537165d7912e4c514f6d49272f9dd60d0adde..505d59c5ea84b6933113819a9cdf420013250f36 100644 |
--- a/content/renderer/media/webrtc/video_destination_handler.cc |
+++ b/content/renderer/media/webrtc/video_destination_handler.cc |
@@ -41,6 +41,13 @@ class PpFrameWriter::FrameWriterDelegate |
private: |
friend class base::RefCountedThreadSafe<FrameWriterDelegate>; |
+ // Endian in memory order, e.g. AXXX stands for uint8 pixel[4] = {A, x, x, x}; |
+ enum PixelEndian { |
+ UNKNOWN, |
+ AXXX, |
+ XXXA, |
+ }; |
+ |
virtual ~FrameWriterDelegate(); |
void StartDeliverOnIO(const VideoCaptureDeliverFrameCB& frame_callback); |
@@ -52,9 +59,11 @@ class PpFrameWriter::FrameWriterDelegate |
scoped_refptr<base::MessageLoopProxy> io_message_loop_; |
- // |frame_pool_| and |new_frame_callback_| are only used on the IO-thread. |
+ // |frame_pool_|, |new_frame_callback_| and |endian_| are only used on the |
+ // IO-thread. |
media::VideoFramePool frame_pool_; |
VideoCaptureDeliverFrameCB new_frame_callback_; |
+ PixelEndian endian_; |
// Used to DCHECK that we are called on the main render thread. |
base::ThreadChecker thread_checker_; |
@@ -62,7 +71,7 @@ class PpFrameWriter::FrameWriterDelegate |
PpFrameWriter::FrameWriterDelegate::FrameWriterDelegate( |
const scoped_refptr<base::MessageLoopProxy>& io_message_loop_proxy) |
- : io_message_loop_(io_message_loop_proxy) { |
+ : io_message_loop_(io_message_loop_proxy), endian_(UNKNOWN) { |
} |
PpFrameWriter::FrameWriterDelegate::~FrameWriterDelegate() { |
@@ -101,6 +110,8 @@ void PpFrameWriter::FrameWriterDelegate::DeliverFrame( |
<< "The image_data's mapped bitmap is NULL."; |
return; |
} |
+ // We only support PP_IMAGEDATAFORMAT_BGRA_PREMUL at the moment. |
+ DCHECK(image_data->format() == PP_IMAGEDATAFORMAT_BGRA_PREMUL); |
io_message_loop_->PostTaskAndReply( |
FROM_HERE, |
base::Bind(&FrameWriterDelegate::DeliverFrameOnIO, this, |
@@ -153,15 +164,46 @@ void PpFrameWriter::FrameWriterDelegate::DeliverFrameOnIO( |
MediaStreamVideoSource::kUnknownFrameRate, |
media::PIXEL_FORMAT_YV12); |
- libyuv::BGRAToI420(data, |
- stride, |
- new_frame->data(media::VideoFrame::kYPlane), |
- new_frame->stride(media::VideoFrame::kYPlane), |
- new_frame->data(media::VideoFrame::kUPlane), |
- new_frame->stride(media::VideoFrame::kUPlane), |
- new_frame->data(media::VideoFrame::kVPlane), |
- new_frame->stride(media::VideoFrame::kVPlane), |
- frame_size.width(), frame_size.height()); |
+ // TODO(magjed): Remove this and always use libyuv::ARGBToI420 when |
+ // crbug/426020 is fixed. |
+ // Due to a change in endianness, we try to determine it from the data. |
+ // The alpha channel is always 255. It is unlikely for other color channels to |
+ // be 255, so we will most likely break on the first few pixels in the first |
+ // frame. |
+ uint8* row_ptr = data; |
+ // Note that we only do this if endian_ is still UNKNOWN. |
+ for (int y = 0; y < height && endian_ == UNKNOWN; ++y) { |
+ for (int x = 0; x < width; ++x) { |
+ if (row_ptr[x * 4 + 0] != 255) { // First byte is not Alpha => XXXA. |
+ endian_ = XXXA; |
+ break; |
+ } |
+ if (row_ptr[x * 4 + 3] != 255) { // Fourth byte is not Alpha => AXXX. |
+ endian_ = AXXX; |
+ break; |
+ } |
+ } |
+ row_ptr += stride; |
+ } |
+ if (endian_ == UNKNOWN) { |
+ LOG(WARNING) << "PpFrameWriter::FrameWriterDelegate::DeliverFrameOnIO - " |
+ << "Could not determine endianness."; |
+ } |
+ // libyuv specifies fourcc/channel ordering the same as webrtc. That is why |
+ // the naming is reversed compared to PixelEndian and PP_ImageDataFormat which |
+ // describes the memory layout from the lowest address to the highest. |
+ const auto* xxxxToI420 = |
+ (endian_ == AXXX) ? &libyuv::BGRAToI420 : &libyuv::ARGBToI420; |
+ xxxxToI420(data, |
+ stride, |
+ new_frame->data(media::VideoFrame::kYPlane), |
+ new_frame->stride(media::VideoFrame::kYPlane), |
+ new_frame->data(media::VideoFrame::kUPlane), |
+ new_frame->stride(media::VideoFrame::kUPlane), |
+ new_frame->data(media::VideoFrame::kVPlane), |
+ new_frame->stride(media::VideoFrame::kVPlane), |
+ width, |
+ height); |
// The local time when this frame is generated is unknown so give a null |
// value to |estimated_capture_time|. |