diff options
-rw-r--r-- | chrome/renderer/media/cast_rtp_stream.cc | 14 | ||||
-rw-r--r-- | content/renderer/media/canvas_capture_handler.cc | 34 | ||||
-rw-r--r-- | content/renderer/media/canvas_capture_handler_unittest.cc | 53 | ||||
-rw-r--r-- | content/renderer/media/media_stream_video_renderer_sink_unittest.cc | 45 | ||||
-rw-r--r-- | content/renderer/media/media_stream_video_track.cc | 6 | ||||
-rw-r--r-- | content/renderer/media/video_track_adapter.cc | 4 | ||||
-rw-r--r-- | content/renderer/media/video_track_recorder.cc | 14 | ||||
-rw-r--r-- | content/renderer/media/webmediaplayer_ms.cc | 2 | ||||
-rw-r--r-- | content/renderer/media/webrtc/webrtc_video_capturer_adapter.cc | 16 | ||||
-rw-r--r-- | content/renderer/pepper/pepper_media_stream_video_track_host.cc | 9 | ||||
-rw-r--r-- | content/renderer/pepper/pepper_video_source_host.cc | 14 | ||||
-rw-r--r-- | media/base/mac/video_frame_mac_unittests.cc | 2 | ||||
-rw-r--r-- | media/base/video_frame.cc | 41 | ||||
-rw-r--r-- | media/base/video_frame.h | 1 | ||||
-rw-r--r-- | media/base/video_frame_pool.cc | 2 | ||||
-rw-r--r-- | media/base/video_frame_unittest.cc | 5 | ||||
-rw-r--r-- | media/base/video_util.cc | 23 | ||||
-rw-r--r-- | media/base/video_util.h | 5 |
18 files changed, 228 insertions, 62 deletions
diff --git a/chrome/renderer/media/cast_rtp_stream.cc b/chrome/renderer/media/cast_rtp_stream.cc index 3c7d101..fb5afff 100644 --- a/chrome/renderer/media/cast_rtp_stream.cc +++ b/chrome/renderer/media/cast_rtp_stream.cc @@ -30,6 +30,7 @@ #include "media/base/bind_to_current_loop.h" #include "media/base/limits.h" #include "media/base/video_frame.h" +#include "media/base/video_util.h" #include "media/cast/cast_config.h" #include "media/cast/cast_sender.h" #include "media/cast/net/cast_transport_config.h" @@ -322,12 +323,23 @@ class CastVideoSink : public base::SupportsWeakPtr<CastVideoSink>, const CastRtpStream::ErrorCallback& error_callback, const scoped_refptr<media::cast::VideoFrameInput> frame_input, // These parameters are passed for each frame. - const scoped_refptr<media::VideoFrame>& frame, + const scoped_refptr<media::VideoFrame>& video_frame, base::TimeTicks estimated_capture_time) { const base::TimeTicks timestamp = estimated_capture_time.is_null() ? base::TimeTicks::Now() : estimated_capture_time; + if (!(video_frame->format() == media::PIXEL_FORMAT_I420 || + video_frame->format() == media::PIXEL_FORMAT_YV12 || + video_frame->format() == media::PIXEL_FORMAT_YV12A)) { + NOTREACHED(); + return; + } + scoped_refptr<media::VideoFrame> frame = video_frame; + // Drop alpha channel since we do not support it yet. + if (frame->format() == media::PIXEL_FORMAT_YV12A) + frame = media::WrapAsI420VideoFrame(video_frame); + // Used by chrome/browser/extension/api/cast_streaming/performance_test.cc TRACE_EVENT_INSTANT2( "cast_perf_test", "MediaStreamVideoSink::OnVideoFrame", diff --git a/content/renderer/media/canvas_capture_handler.cc b/content/renderer/media/canvas_capture_handler.cc index 634267e..4a44740 100644 --- a/content/renderer/media/canvas_capture_handler.cc +++ b/content/renderer/media/canvas_capture_handler.cc @@ -39,11 +39,13 @@ class CanvasCaptureHandler::VideoCapturerSource double max_requested_frame_rate, const VideoCaptureDeviceFormatsCB& callback) override { const blink::WebSize& size = canvas_handler_->GetSourceSize(); - const media::VideoCaptureFormat format(gfx::Size(size.width, size.height), - frame_rate_, - media::PIXEL_FORMAT_I420); media::VideoCaptureFormats formats; - formats.push_back(format); + formats.push_back( + media::VideoCaptureFormat(gfx::Size(size.width, size.height), + frame_rate_, media::PIXEL_FORMAT_I420)); + formats.push_back( + media::VideoCaptureFormat(gfx::Size(size.width, size.height), + frame_rate_, media::PIXEL_FORMAT_YV12A)); callback.Run(formats); } void StartCapture(const media::VideoCaptureParams& params, @@ -166,8 +168,8 @@ void CanvasCaptureHandler::StopVideoCapture() { void CanvasCaptureHandler::CreateNewFrame(const SkImage* image) { DCHECK(thread_checker_.CalledOnValidThread()); - DCHECK(image); + const gfx::Size size(image->width(), image->height()); if (size != last_size) { temp_data_.resize( @@ -176,16 +178,23 @@ void CanvasCaptureHandler::CreateNewFrame(const SkImage* image) { media::VideoFrame::RowBytes(0, media::PIXEL_FORMAT_ARGB, size.width()); image_info_ = SkImageInfo::Make(size.width(), size.height(), kBGRA_8888_SkColorType, - kPremul_SkAlphaType); + kUnpremul_SkAlphaType); last_size = size; } - image->readPixels(image_info_, &temp_data_[0], row_bytes_, 0, 0); - scoped_refptr<media::VideoFrame> video_frame = - frame_pool_.CreateFrame(media::PIXEL_FORMAT_I420, size, gfx::Rect(size), - size, base::TimeTicks::Now() - base::TimeTicks()); + if(!image->readPixels(image_info_, &temp_data_[0], row_bytes_, 0, 0)) { + DLOG(ERROR) << "Couldn't read SkImage pixels"; + return; + } + + const bool isOpaque = image->isOpaque(); + scoped_refptr<media::VideoFrame> video_frame = frame_pool_.CreateFrame( + isOpaque ? media::PIXEL_FORMAT_I420 : media::PIXEL_FORMAT_YV12A, size, + gfx::Rect(size), size, base::TimeTicks::Now() - base::TimeTicks()); DCHECK(video_frame); + // TODO(emircan): Use https://code.google.com/p/libyuv/issues/detail?id=572 + // when it becomes available. libyuv::ARGBToI420(temp_data_.data(), row_bytes_, video_frame->data(media::VideoFrame::kYPlane), video_frame->stride(media::VideoFrame::kYPlane), @@ -194,6 +203,11 @@ void CanvasCaptureHandler::CreateNewFrame(const SkImage* image) { video_frame->data(media::VideoFrame::kVPlane), video_frame->stride(media::VideoFrame::kVPlane), size.width(), size.height()); + if (!isOpaque) { + for (int p = 0; p < size.GetArea(); ++p) + video_frame->data(media::VideoFrame::kAPlane)[p] = temp_data_[p * 4 + 3]; + } + io_task_runner_->PostTask( FROM_HERE, base::Bind(&CanvasCaptureHandler::CanvasCaptureHandlerDelegate:: diff --git a/content/renderer/media/canvas_capture_handler_unittest.cc b/content/renderer/media/canvas_capture_handler_unittest.cc index 8519bd1..8c449a3 100644 --- a/content/renderer/media/canvas_capture_handler_unittest.cc +++ b/content/renderer/media/canvas_capture_handler_unittest.cc @@ -22,9 +22,12 @@ using ::testing::InSequence; using ::testing::Mock; using ::testing::SaveArg; using ::testing::Test; +using ::testing::TestWithParam; namespace content { +namespace { + static const int kTestCanvasCaptureWidth = 320; static const int kTestCanvasCaptureHeight = 240; static const double kTestCanvasCaptureFramesPerSecond = 55.5; @@ -32,12 +35,15 @@ static const double kTestCanvasCaptureFramesPerSecond = 55.5; static const int kTestCanvasCaptureFrameWidth = 2; static const int kTestCanvasCaptureFrameHeight = 2; static const int kTestCanvasCaptureFrameErrorTolerance = 2; +static const int kTestAlphaValue = 175; ACTION_P(RunClosure, closure) { closure.Run(); } -class CanvasCaptureHandlerTest : public Test { +} // namespace + +class CanvasCaptureHandlerTest : public TestWithParam<bool> { public: CanvasCaptureHandlerTest() {} @@ -76,27 +82,37 @@ class CanvasCaptureHandlerTest : public Test { void OnRunning(bool state) { DoOnRunning(state); } // Verify returned frames. - static skia::RefPtr<SkImage> GenerateTestImage() { + static skia::RefPtr<SkImage> GenerateTestImage(bool opaque) { + SkBitmap testBitmap; testBitmap.allocN32Pixels(kTestCanvasCaptureFrameWidth, - kTestCanvasCaptureFrameHeight); - testBitmap.eraseColor(SK_ColorBLUE); + kTestCanvasCaptureFrameHeight, opaque); + testBitmap.eraseARGB(kTestAlphaValue, 30, 60, 200); return skia::AdoptRef(SkImage::NewFromBitmap(testBitmap)); } void OnVerifyDeliveredFrame( + bool opaque, const scoped_refptr<media::VideoFrame>& video_frame, base::TimeTicks estimated_capture_time) { - EXPECT_EQ(media::PIXEL_FORMAT_I420, video_frame->format()); + if (opaque) + EXPECT_EQ(media::PIXEL_FORMAT_I420, video_frame->format()); + else + EXPECT_EQ(media::PIXEL_FORMAT_YV12A, video_frame->format()); + const gfx::Size& size = video_frame->coded_size(); EXPECT_EQ(kTestCanvasCaptureFrameWidth, size.width()); EXPECT_EQ(kTestCanvasCaptureFrameHeight, size.height()); - const uint8_t* y_plane = video_frame->data(0); - EXPECT_NEAR(41, y_plane[0], kTestCanvasCaptureFrameErrorTolerance); - const uint8_t* u_plane = video_frame->data(1); - EXPECT_NEAR(239, u_plane[0], kTestCanvasCaptureFrameErrorTolerance); - const uint8_t* v_plane = video_frame->data(2); - EXPECT_NEAR(110, v_plane[0], kTestCanvasCaptureFrameErrorTolerance); + const uint8_t* y_plane = video_frame->data(media::VideoFrame::kYPlane); + EXPECT_NEAR(74, y_plane[0], kTestCanvasCaptureFrameErrorTolerance); + const uint8_t* u_plane = video_frame->data(media::VideoFrame::kUPlane); + EXPECT_NEAR(193, u_plane[0], kTestCanvasCaptureFrameErrorTolerance); + const uint8_t* v_plane = video_frame->data(media::VideoFrame::kVPlane); + EXPECT_NEAR(105, v_plane[0], kTestCanvasCaptureFrameErrorTolerance); + if (!opaque) { + const uint8_t* a_plane = video_frame->data(media::VideoFrame::kAPlane); + EXPECT_EQ(kTestAlphaValue, a_plane[0]); + } } blink::WebMediaStreamTrack track_; @@ -125,7 +141,7 @@ TEST_F(CanvasCaptureHandlerTest, ConstructAndDestruct) { } // Checks that VideoCapturerSource call sequence works fine. -TEST_F(CanvasCaptureHandlerTest, GetFormatsStartAndStop) { +TEST_P(CanvasCaptureHandlerTest, GetFormatsStartAndStop) { InSequence s; const blink::WebMediaStreamSource& web_media_stream_source = track_.source(); EXPECT_FALSE(web_media_stream_source.isNull()); @@ -146,7 +162,7 @@ TEST_F(CanvasCaptureHandlerTest, GetFormatsStartAndStop) { media::limits::kMaxFramesPerSecond /* max_requested_frame_rate */, base::Bind(&CanvasCaptureHandlerTest::OnVideoCaptureDeviceFormats, base::Unretained(this))); - ASSERT_EQ(1u, formats.size()); + ASSERT_EQ(2u, formats.size()); EXPECT_EQ(kTestCanvasCaptureWidth, formats[0].frame_size.width()); EXPECT_EQ(kTestCanvasCaptureHeight, formats[0].frame_size.height()); media::VideoCaptureParams params; @@ -162,14 +178,15 @@ TEST_F(CanvasCaptureHandlerTest, GetFormatsStartAndStop) { params, base::Bind(&CanvasCaptureHandlerTest::OnDeliverFrame, base::Unretained(this)), base::Bind(&CanvasCaptureHandlerTest::OnRunning, base::Unretained(this))); - canvas_capture_handler_->sendNewFrame(GenerateTestImage().get()); + canvas_capture_handler_->sendNewFrame(GenerateTestImage(GetParam()).get()); run_loop.Run(); source->StopCapture(); } // Verifies that SkImage is processed and produces VideoFrame as expected. -TEST_F(CanvasCaptureHandlerTest, VerifyFrame) { +TEST_P(CanvasCaptureHandlerTest, VerifyOpaqueFrame) { + const bool isOpaque = GetParam(); InSequence s; media::VideoCapturerSource* const source = GetVideoCapturerSource(static_cast<MediaStreamVideoCapturerSource*>( @@ -181,9 +198,9 @@ TEST_F(CanvasCaptureHandlerTest, VerifyFrame) { media::VideoCaptureParams params; source->StartCapture( params, base::Bind(&CanvasCaptureHandlerTest::OnVerifyDeliveredFrame, - base::Unretained(this)), + base::Unretained(this), isOpaque), base::Bind(&CanvasCaptureHandlerTest::OnRunning, base::Unretained(this))); - canvas_capture_handler_->sendNewFrame(GenerateTestImage().get()); + canvas_capture_handler_->sendNewFrame(GenerateTestImage(isOpaque).get()); run_loop.RunUntilIdle(); } @@ -199,4 +216,6 @@ TEST_F(CanvasCaptureHandlerTest, CheckNeedsNewFrame) { EXPECT_FALSE(canvas_capture_handler_->needsNewFrame()); } +INSTANTIATE_TEST_CASE_P(, CanvasCaptureHandlerTest, ::testing::Bool()); + } // namespace content diff --git a/content/renderer/media/media_stream_video_renderer_sink_unittest.cc b/content/renderer/media/media_stream_video_renderer_sink_unittest.cc index 32b23e3..77edaf8 100644 --- a/content/renderer/media/media_stream_video_renderer_sink_unittest.cc +++ b/content/renderer/media/media_stream_video_renderer_sink_unittest.cc @@ -39,12 +39,11 @@ class MediaStreamVideoRendererSinkTest : public testing::Test { registry_.AddVideoTrack(kTestVideoTrackId); // Extract the Blink Video Track for the MSVRSink. - blink::WebVector<blink::WebMediaStreamTrack> video_tracks; - registry_.test_stream().videoTracks(video_tracks); - EXPECT_EQ(1u, video_tracks.size()); + registry_.test_stream().videoTracks(video_tracks_); + EXPECT_EQ(1u, video_tracks_.size()); media_stream_video_renderer_sink_ = new MediaStreamVideoRendererSink( - video_tracks[0], + video_tracks_[0], base::Bind(&MediaStreamVideoRendererSinkTest::ErrorCallback, base::Unretained(this)), base::Bind(&MediaStreamVideoRendererSinkTest::RepaintCallback, @@ -91,6 +90,8 @@ class MediaStreamVideoRendererSinkTest : public testing::Test { // and Sources in |registry_| into believing they are on the right threads. base::MessageLoopForUI message_loop_; const ChildProcess child_process_; + + blink::WebVector<blink::WebMediaStreamTrack> video_tracks_; MockMediaStreamRegistry registry_; private: @@ -158,4 +159,40 @@ TEST_F(MediaStreamVideoRendererSinkAsyncAddFrameReadyTest, media_stream_video_renderer_sink_->Stop(); } +class MediaStreamVideoRendererSinkTransparencyTest + : public MediaStreamVideoRendererSinkTest { + public: + MediaStreamVideoRendererSinkTransparencyTest() { + media_stream_video_renderer_sink_ = new MediaStreamVideoRendererSink( + video_tracks_[0], + base::Bind(&MediaStreamVideoRendererSinkTest::ErrorCallback, + base::Unretained(this)), + base::Bind(&MediaStreamVideoRendererSinkTransparencyTest:: + VerifyTransparentFrame, + base::Unretained(this)), + message_loop_.task_runner(), message_loop_.task_runner().get(), + nullptr /* gpu_factories */); + } + + void VerifyTransparentFrame(const scoped_refptr<media::VideoFrame>& frame) { + EXPECT_EQ(media::PIXEL_FORMAT_YV12A, frame->format()); + } +}; + +TEST_F(MediaStreamVideoRendererSinkTransparencyTest, + SendTransparentFrame) { + media_stream_video_renderer_sink_->Start(); + + InSequence s; + const gfx::Size kSize(10, 10); + const base::TimeDelta kTimestamp = base::TimeDelta(); + const scoped_refptr<media::VideoFrame> video_frame = + media::VideoFrame::CreateFrame(media::PIXEL_FORMAT_YV12A, kSize, + gfx::Rect(kSize), kSize, kTimestamp); + OnVideoFrame(video_frame); + message_loop_.RunUntilIdle(); + + media_stream_video_renderer_sink_->Stop(); +} + } // namespace content diff --git a/content/renderer/media/media_stream_video_track.cc b/content/renderer/media/media_stream_video_track.cc index 6ff4688..e9cc8e0 100644 --- a/content/renderer/media/media_stream_video_track.cc +++ b/content/renderer/media/media_stream_video_track.cc @@ -175,9 +175,9 @@ MediaStreamVideoTrack::FrameDeliverer::GetBlackFrame( // Wrap |black_frame_| so we get a fresh timestamp we can modify. Frames // returned from this function may still be in use. scoped_refptr<media::VideoFrame> wrapped_black_frame = - media::VideoFrame::WrapVideoFrame( - black_frame_, black_frame_->visible_rect(), - black_frame_->natural_size()); + media::VideoFrame::WrapVideoFrame(black_frame_, black_frame_->format(), + black_frame_->visible_rect(), + black_frame_->natural_size()); if (!wrapped_black_frame) return nullptr; wrapped_black_frame->AddDestructionObserver( diff --git a/content/renderer/media/video_track_adapter.cc b/content/renderer/media/video_track_adapter.cc index f4ca1d2..bf737bd 100644 --- a/content/renderer/media/video_track_adapter.cc +++ b/content/renderer/media/video_track_adapter.cc @@ -266,8 +266,8 @@ void VideoTrackAdapter::VideoFrameResolutionAdapter::DeliverFrame( const gfx::Rect region_in_frame = media::ComputeLetterboxRegion(frame->visible_rect(), desired_size); - video_frame = - media::VideoFrame::WrapVideoFrame(frame, region_in_frame, desired_size); + video_frame = media::VideoFrame::WrapVideoFrame( + frame, frame->format(), region_in_frame, desired_size); if (!video_frame) return; video_frame->AddDestructionObserver( diff --git a/content/renderer/media/video_track_recorder.cc b/content/renderer/media/video_track_recorder.cc index 1dc73b7..390a0ff 100644 --- a/content/renderer/media/video_track_recorder.cc +++ b/content/renderer/media/video_track_recorder.cc @@ -14,6 +14,7 @@ #include "base/time/time.h" #include "base/trace_event/trace_event.h" #include "media/base/video_frame.h" +#include "media/base/video_util.h" #include "ui/gfx/geometry/size.h" extern "C" { @@ -186,12 +187,23 @@ void VideoTrackRecorder::VpxEncoder::StartFrameEncode( } void VideoTrackRecorder::VpxEncoder::EncodeOnEncodingThread( - const scoped_refptr<VideoFrame>& frame, + const scoped_refptr<VideoFrame>& video_frame, base::TimeTicks capture_timestamp) { TRACE_EVENT0("video", "VideoTrackRecorder::VpxEncoder::EncodeOnEncodingThread"); DCHECK(encoding_thread_->task_runner()->BelongsToCurrentThread()); + if (!(video_frame->format() == media::PIXEL_FORMAT_I420 || + video_frame->format() == media::PIXEL_FORMAT_YV12 || + video_frame->format() == media::PIXEL_FORMAT_YV12A)) { + NOTREACHED(); + return; + } + scoped_refptr<media::VideoFrame> frame = video_frame; + // Drop alpha channel since we do not support it yet. + if (frame->format() == media::PIXEL_FORMAT_YV12A) + frame = media::WrapAsI420VideoFrame(video_frame); + const gfx::Size frame_size = frame->visible_rect().size(); if (!IsInitialized() || gfx::Size(codec_config_.g_w, codec_config_.g_h) != frame_size) { diff --git a/content/renderer/media/webmediaplayer_ms.cc b/content/renderer/media/webmediaplayer_ms.cc index 9f59a76..4134b84 100644 --- a/content/renderer/media/webmediaplayer_ms.cc +++ b/content/renderer/media/webmediaplayer_ms.cc @@ -495,7 +495,7 @@ void WebMediaPlayerMS::OnFrameAvailable( video_weblayer_.reset(new cc_blink::WebLayerImpl( cc::VideoLayer::Create(cc::LayerSettings(), compositor_.get(), media::VIDEO_ROTATION_0))); - video_weblayer_->layer()->SetContentsOpaque(true); + video_weblayer_->layer()->SetContentsOpaque(false); video_weblayer_->SetContentsOpaqueIsFixed(true); get_client()->setWebLayer(video_weblayer_.get()); } diff --git a/content/renderer/media/webrtc/webrtc_video_capturer_adapter.cc b/content/renderer/media/webrtc/webrtc_video_capturer_adapter.cc index 962164c..10ad857 100644 --- a/content/renderer/media/webrtc/webrtc_video_capturer_adapter.cc +++ b/content/renderer/media/webrtc/webrtc_video_capturer_adapter.cc @@ -11,6 +11,7 @@ #include "media/base/timestamp_constants.h" #include "media/base/video_frame.h" #include "media/base/video_frame_pool.h" +#include "media/base/video_util.h" #include "third_party/libyuv/include/libyuv/convert_from.h" #include "third_party/libyuv/include/libyuv/scale.h" #include "third_party/webrtc/common_video/include/video_frame_buffer.h" @@ -94,7 +95,8 @@ class WebRtcVideoCapturerAdapter::MediaVideoFrameFactory const gfx::Size output_size(output_width, output_height); scoped_refptr<media::VideoFrame> video_frame = - media::VideoFrame::WrapVideoFrame(frame_, visible_rect, output_size); + media::VideoFrame::WrapVideoFrame(frame_, frame_->format(), + visible_rect, output_size); if (!video_frame) return nullptr; video_frame->AddDestructionObserver( @@ -216,16 +218,22 @@ bool WebRtcVideoCapturerAdapter::GetBestCaptureFormat( } void WebRtcVideoCapturerAdapter::OnFrameCaptured( - const scoped_refptr<media::VideoFrame>& frame) { + const scoped_refptr<media::VideoFrame>& video_frame) { DCHECK(thread_checker_.CalledOnValidThread()); TRACE_EVENT0("video", "WebRtcVideoCapturerAdapter::OnFrameCaptured"); - if (!(frame->IsMappable() && (frame->format() == media::PIXEL_FORMAT_I420 || - frame->format() == media::PIXEL_FORMAT_YV12))) { + if (!(video_frame->IsMappable() && + (video_frame->format() == media::PIXEL_FORMAT_I420 || + video_frame->format() == media::PIXEL_FORMAT_YV12 || + video_frame->format() == media::PIXEL_FORMAT_YV12A))) { // Since connecting sources and sinks do not check the format, we need to // just ignore formats that we can not handle. NOTREACHED(); return; } + scoped_refptr<media::VideoFrame> frame = video_frame; + // Drop alpha channel since we do not support it yet. + if (frame->format() == media::PIXEL_FORMAT_YV12A) + frame = media::WrapAsI420VideoFrame(video_frame); // Inject the frame via the VideoFrameFactory of base class. MediaVideoFrameFactory* media_video_frame_factory = diff --git a/content/renderer/pepper/pepper_media_stream_video_track_host.cc b/content/renderer/pepper/pepper_media_stream_video_track_host.cc index d0e47c2..e834b10 100644 --- a/content/renderer/pepper/pepper_media_stream_video_track_host.cc +++ b/content/renderer/pepper/pepper_media_stream_video_track_host.cc @@ -13,6 +13,7 @@ #include "base/strings/utf_string_conversions.h" #include "content/renderer/media/media_stream_video_track.h" #include "media/base/bind_to_current_loop.h" +#include "media/base/video_util.h" #include "media/base/yuv_convert.h" #include "ppapi/c/pp_errors.h" #include "ppapi/c/ppb_media_stream_video_track.h" @@ -370,10 +371,14 @@ int32_t PepperMediaStreamVideoTrackHost::SendFrameToTrack(int32_t index) { } void PepperMediaStreamVideoTrackHost::OnVideoFrame( - const scoped_refptr<VideoFrame>& frame, + const scoped_refptr<VideoFrame>& video_frame, base::TimeTicks estimated_capture_time) { - DCHECK(frame.get()); + DCHECK(video_frame.get()); // TODO(penghuang): Check |frame->end_of_stream()| and close the track. + scoped_refptr<media::VideoFrame> frame = video_frame; + // Drop alpha channel since we do not support it yet. + if (frame->format() == media::PIXEL_FORMAT_YV12A) + frame = media::WrapAsI420VideoFrame(video_frame); PP_VideoFrame_Format ppformat = ToPpapiFormat(frame->format()); if (ppformat == PP_VIDEOFRAME_FORMAT_UNKNOWN) return; diff --git a/content/renderer/pepper/pepper_video_source_host.cc b/content/renderer/pepper/pepper_video_source_host.cc index db20126..cac83eb 100644 --- a/content/renderer/pepper/pepper_video_source_host.cc +++ b/content/renderer/pepper/pepper_video_source_host.cc @@ -12,6 +12,7 @@ #include "content/renderer/media/video_track_to_pepper_adapter.h" #include "content/renderer/pepper/ppb_image_data_impl.h" #include "content/renderer/render_thread_impl.h" +#include "media/base/video_util.h" #include "ppapi/c/pp_errors.h" #include "ppapi/host/dispatch_host_message.h" #include "ppapi/host/ppapi_host.h" @@ -55,10 +56,21 @@ PepperVideoSourceHost::FrameReceiver::FrameReceiver( PepperVideoSourceHost::FrameReceiver::~FrameReceiver() {} void PepperVideoSourceHost::FrameReceiver::GotFrame( - const scoped_refptr<media::VideoFrame>& frame) { + const scoped_refptr<media::VideoFrame>& video_frame) { DCHECK(thread_checker_.CalledOnValidThread()); if (!host_) return; + + if (!(video_frame->format() == media::PIXEL_FORMAT_I420 || + video_frame->format() == media::PIXEL_FORMAT_YV12A)) { + NOTREACHED(); + return; + } + scoped_refptr<media::VideoFrame> frame = video_frame; + // Drop alpha channel since we do not support it yet. + if (frame->format() == media::PIXEL_FORMAT_YV12A) + frame = media::WrapAsI420VideoFrame(video_frame); + // Hold a reference to the new frame and release the previous. host_->last_frame_ = frame; if (host_->get_frame_pending_) diff --git a/media/base/mac/video_frame_mac_unittests.cc b/media/base/mac/video_frame_mac_unittests.cc index 475d9aa..c0d8109 100644 --- a/media/base/mac/video_frame_mac_unittests.cc +++ b/media/base/mac/video_frame_mac_unittests.cc @@ -94,7 +94,7 @@ TEST(VideoFrameMac, CheckLifetime) { int instances_destroyed = 0; auto wrapper_frame = VideoFrame::WrapVideoFrame( - frame, frame->visible_rect(), frame->natural_size()); + frame, frame->format(), frame->visible_rect(), frame->natural_size()); wrapper_frame->AddDestructionObserver( base::Bind(&Increment, &instances_destroyed)); ASSERT_TRUE(wrapper_frame.get()); diff --git a/media/base/video_frame.cc b/media/base/video_frame.cc index ea7370b..b4a8392f 100644 --- a/media/base/video_frame.cc +++ b/media/base/video_frame.cc @@ -83,6 +83,18 @@ static bool IsStorageTypeMappable(VideoFrame::StorageType storage_type) { storage_type == VideoFrame::STORAGE_MOJO_SHARED_BUFFER); } +// Checks if |source_format| can be wrapped into a |target_format| frame. +static bool AreValidPixelFormatsForWrap(VideoPixelFormat source_format, + VideoPixelFormat target_format) { + if (source_format == target_format) + return true; + + // It is possible to add other planar to planar format conversions here if the + // use case is there. + return source_format == PIXEL_FORMAT_YV12A && + target_format == PIXEL_FORMAT_I420; +} + // static bool VideoFrame::IsValidConfig(VideoPixelFormat format, StorageType storage_type, @@ -378,32 +390,39 @@ scoped_refptr<VideoFrame> VideoFrame::WrapCVPixelBuffer( // static scoped_refptr<VideoFrame> VideoFrame::WrapVideoFrame( - const scoped_refptr<VideoFrame>& frame, - const gfx::Rect& visible_rect, - const gfx::Size& natural_size) { + const scoped_refptr<VideoFrame>& frame, + VideoPixelFormat format, + const gfx::Rect& visible_rect, + const gfx::Size& natural_size) { // Frames with textures need mailbox info propagated, and there's no support // for that here yet, see http://crbug/362521. CHECK(!frame->HasTextures()); - DCHECK(frame->visible_rect().Contains(visible_rect)); - if (!IsValidConfig(frame->format(), frame->storage_type(), - frame->coded_size(), visible_rect, natural_size)) { + if (!AreValidPixelFormatsForWrap(frame->format(), format)) { + LOG(DFATAL) << __FUNCTION__ << " Invalid format conversion." + << VideoPixelFormatToString(frame->format()) << " to " + << VideoPixelFormatToString(format); + return nullptr; + } + + if (!IsValidConfig(format, frame->storage_type(), frame->coded_size(), + visible_rect, natural_size)) { LOG(DFATAL) << __FUNCTION__ << " Invalid config." - << ConfigToString(frame->format(), frame->storage_type(), + << ConfigToString(format, frame->storage_type(), frame->coded_size(), visible_rect, natural_size); return nullptr; } - scoped_refptr<VideoFrame> wrapping_frame(new VideoFrame( - frame->format(), frame->storage_type(), frame->coded_size(), visible_rect, - natural_size, frame->timestamp())); + scoped_refptr<VideoFrame> wrapping_frame( + new VideoFrame(format, frame->storage_type(), frame->coded_size(), + visible_rect, natural_size, frame->timestamp())); // Copy all metadata to the wrapped frame. wrapping_frame->metadata()->MergeMetadataFrom(frame->metadata()); - for (size_t i = 0; i < NumPlanes(frame->format()); ++i) { + for (size_t i = 0; i < NumPlanes(format); ++i) { wrapping_frame->strides_[i] = frame->stride(i); wrapping_frame->data_[i] = frame->data(i); } diff --git a/media/base/video_frame.h b/media/base/video_frame.h index 9538d7a..944a040 100644 --- a/media/base/video_frame.h +++ b/media/base/video_frame.h @@ -245,6 +245,7 @@ class MEDIA_EXPORT VideoFrame : public base::RefCountedThreadSafe<VideoFrame> { // frame->visible_rect(). static scoped_refptr<VideoFrame> WrapVideoFrame( const scoped_refptr<VideoFrame>& frame, + VideoPixelFormat format, const gfx::Rect& visible_rect, const gfx::Size& natural_size); diff --git a/media/base/video_frame_pool.cc b/media/base/video_frame_pool.cc index 40611ee..2bc7ff6 100644 --- a/media/base/video_frame_pool.cc +++ b/media/base/video_frame_pool.cc @@ -86,7 +86,7 @@ scoped_refptr<VideoFrame> VideoFramePool::PoolImpl::CreateFrame( } scoped_refptr<VideoFrame> wrapped_frame = VideoFrame::WrapVideoFrame( - frame, frame->visible_rect(), frame->natural_size()); + frame, frame->format(), frame->visible_rect(), frame->natural_size()); wrapped_frame->AddDestructionObserver( base::Bind(&VideoFramePool::PoolImpl::FrameReleased, this, frame)); return wrapped_frame; diff --git a/media/base/video_frame_unittest.cc b/media/base/video_frame_unittest.cc index 1b45ea8..79652bb 100644 --- a/media/base/video_frame_unittest.cc +++ b/media/base/video_frame_unittest.cc @@ -242,11 +242,10 @@ TEST(VideoFrame, WrapVideoFrame) { gfx::Size natural_size = visible_rect.size(); wrapped_frame->metadata()->SetTimeDelta( media::VideoFrameMetadata::FRAME_DURATION, kFrameDuration); - frame = media::VideoFrame::WrapVideoFrame(wrapped_frame, visible_rect, - natural_size); + frame = media::VideoFrame::WrapVideoFrame( + wrapped_frame, wrapped_frame->format(), visible_rect, natural_size); frame->AddDestructionObserver(base::Bind( &FrameNoLongerNeededCallback, wrapped_frame, &done_callback_was_run)); - EXPECT_EQ(wrapped_frame->coded_size(), frame->coded_size()); EXPECT_EQ(wrapped_frame->data(media::VideoFrame::kYPlane), frame->data(media::VideoFrame::kYPlane)); diff --git a/media/base/video_util.cc b/media/base/video_util.cc index c628673..d9954f8 100644 --- a/media/base/video_util.cc +++ b/media/base/video_util.cc @@ -14,6 +14,13 @@ namespace media { +namespace { + +// Empty method used for keeping a reference to the original media::VideoFrame. +void ReleaseOriginalFrame(const scoped_refptr<media::VideoFrame>& frame) {} + +} // namespace + gfx::Size GetNaturalSize(const gfx::Size& visible_size, int aspect_ratio_numerator, int aspect_ratio_denominator) { @@ -316,4 +323,20 @@ void CopyRGBToVideoFrame(const uint8_t* source, uv_stride); } +scoped_refptr<VideoFrame> WrapAsI420VideoFrame( + const scoped_refptr<VideoFrame>& frame) { + DCHECK_EQ(VideoFrame::STORAGE_OWNED_MEMORY, frame->storage_type()); + DCHECK_EQ(PIXEL_FORMAT_YV12A, frame->format()); + + scoped_refptr<media::VideoFrame> wrapped_frame = + media::VideoFrame::WrapVideoFrame(frame, PIXEL_FORMAT_I420, + frame->visible_rect(), + frame->natural_size()); + if (!wrapped_frame) + return nullptr; + wrapped_frame->AddDestructionObserver( + base::Bind(&ReleaseOriginalFrame, frame)); + return wrapped_frame; +} + } // namespace media diff --git a/media/base/video_util.h b/media/base/video_util.h index e513433..2dec7e9 100644 --- a/media/base/video_util.h +++ b/media/base/video_util.h @@ -7,6 +7,7 @@ #include <stdint.h> +#include "base/memory/ref_counted.h" #include "media/base/media_export.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" @@ -92,6 +93,10 @@ MEDIA_EXPORT void CopyRGBToVideoFrame(const uint8_t* source, const gfx::Rect& region_in_frame, VideoFrame* frame); +// Converts a frame with YV12A format into I420 by dropping alpha channel. +MEDIA_EXPORT scoped_refptr<VideoFrame> WrapAsI420VideoFrame( + const scoped_refptr<VideoFrame>& frame); + } // namespace media #endif // MEDIA_BASE_VIDEO_UTIL_H_ |