Commit 86b3f4b2 authored by scherkus@chromium.org's avatar scherkus@chromium.org

Remove --enable-video-logging and WebVideoRenderer.

WebVideoRenderer was added in r40137 as part of my IPC-based video rendering experiment.

I later added --enable-video-logging in r43038 which was intended to log timestamps and do logs analysis to determine playback smoothness. This again was experimental and never used.

Also removed WebMediaPlayerProxy::SetRect() and VideoRendererImpl::SetRect() as they were not implemented.

Review URL: http://codereview.chromium.org/8601004

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@110786 0039d316-1c4b-4281-b951-d872f2087c98
parent b62eab12
...@@ -694,7 +694,6 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer( ...@@ -694,7 +694,6 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer(
switches::kEnableStatsTable, switches::kEnableStatsTable,
switches::kEnableThreadedCompositing, switches::kEnableThreadedCompositing,
switches::kEnableVideoFullscreen, switches::kEnableVideoFullscreen,
switches::kEnableVideoLogging,
switches::kEnableVideoTrack, switches::kEnableVideoTrack,
switches::kFullMemoryCrashReport, switches::kFullMemoryCrashReport,
#if !defined (GOOGLE_CHROME_BUILD) #if !defined (GOOGLE_CHROME_BUILD)
......
...@@ -263,10 +263,6 @@ const char kEnableTouchEvents[] = "enable-touch-events"; ...@@ -263,10 +263,6 @@ const char kEnableTouchEvents[] = "enable-touch-events";
// incomplete and this flag is used for development and testing. // incomplete and this flag is used for development and testing.
const char kEnableVideoFullscreen[] = "enable-video-fullscreen"; const char kEnableVideoFullscreen[] = "enable-video-fullscreen";
// Enables video logging where video elements log playback performance data to
// the debug log.
const char kEnableVideoLogging[] = "enable-video-logging";
// Enables support for video tracks. Current implementation is // Enables support for video tracks. Current implementation is
// incomplete and this flag is used for development and testing. // incomplete and this flag is used for development and testing.
const char kEnableVideoTrack[] = "enable-video-track"; const char kEnableVideoTrack[] = "enable-video-track";
......
...@@ -90,7 +90,6 @@ CONTENT_EXPORT extern const char kEnableThreadedCompositing[]; ...@@ -90,7 +90,6 @@ CONTENT_EXPORT extern const char kEnableThreadedCompositing[];
CONTENT_EXPORT extern const char kEnableTcpFastOpen[]; CONTENT_EXPORT extern const char kEnableTcpFastOpen[];
CONTENT_EXPORT extern const char kEnableTouchEvents[]; CONTENT_EXPORT extern const char kEnableTouchEvents[];
extern const char kEnableVideoFullscreen[]; extern const char kEnableVideoFullscreen[];
extern const char kEnableVideoLogging[];
CONTENT_EXPORT extern const char kEnableVideoTrack[]; CONTENT_EXPORT extern const char kEnableVideoTrack[];
CONTENT_EXPORT extern const char kEnableWebIntents[]; CONTENT_EXPORT extern const char kEnableWebIntents[];
CONTENT_EXPORT extern const char kExperimentalLocationFeatures[]; CONTENT_EXPORT extern const char kExperimentalLocationFeatures[];
......
...@@ -1910,13 +1910,6 @@ WebMediaPlayer* RenderViewImpl::createMediaPlayer( ...@@ -1910,13 +1910,6 @@ WebMediaPlayer* RenderViewImpl::createMediaPlayer(
collection->AddAudioRenderer(new AudioRendererImpl()); collection->AddAudioRenderer(new AudioRendererImpl());
} }
scoped_refptr<webkit_media::WebVideoRenderer> video_renderer;
bool pts_logging = cmd_line->HasSwitch(switches::kEnableVideoLogging);
scoped_refptr<webkit_media::VideoRendererImpl> renderer(
new webkit_media::VideoRendererImpl(pts_logging));
collection->AddVideoRenderer(renderer);
video_renderer = renderer;
scoped_ptr<webkit_media::WebMediaPlayerImpl> result( scoped_ptr<webkit_media::WebMediaPlayerImpl> result(
new webkit_media::WebMediaPlayerImpl(client, new webkit_media::WebMediaPlayerImpl(client,
AsWeakPtr(), AsWeakPtr(),
...@@ -1925,8 +1918,7 @@ WebMediaPlayer* RenderViewImpl::createMediaPlayer( ...@@ -1925,8 +1918,7 @@ WebMediaPlayer* RenderViewImpl::createMediaPlayer(
media_stream_impl_.get(), media_stream_impl_.get(),
new RenderMediaLog())); new RenderMediaLog()));
if (!result->Initialize(frame, if (!result->Initialize(frame,
cmd_line->HasSwitch(switches::kSimpleDataSource), cmd_line->HasSwitch(switches::kSimpleDataSource))) {
video_renderer)) {
return NULL; return NULL;
} }
return result.release(); return result.release();
......
...@@ -13,9 +13,10 @@ ...@@ -13,9 +13,10 @@
namespace webkit_media { namespace webkit_media {
VideoRendererImpl::VideoRendererImpl(bool pts_logging) VideoRendererImpl::VideoRendererImpl(
: last_converted_frame_(NULL), const scoped_refptr<WebMediaPlayerProxy>& proxy)
pts_logging_(pts_logging) { : proxy_(proxy),
last_converted_frame_(NULL) {
} }
VideoRendererImpl::~VideoRendererImpl() {} VideoRendererImpl::~VideoRendererImpl() {}
...@@ -39,12 +40,6 @@ void VideoRendererImpl::OnFrameAvailable() { ...@@ -39,12 +40,6 @@ void VideoRendererImpl::OnFrameAvailable() {
proxy_->Repaint(); proxy_->Repaint();
} }
void VideoRendererImpl::SetWebMediaPlayerProxy(WebMediaPlayerProxy* proxy) {
proxy_ = proxy;
}
void VideoRendererImpl::SetRect(const gfx::Rect& rect) {}
// This method is always called on the renderer's thread. // This method is always called on the renderer's thread.
void VideoRendererImpl::Paint(SkCanvas* canvas, const gfx::Rect& dest_rect) { void VideoRendererImpl::Paint(SkCanvas* canvas, const gfx::Rect& dest_rect) {
scoped_refptr<media::VideoFrame> video_frame; scoped_refptr<media::VideoFrame> video_frame;
...@@ -64,13 +59,6 @@ void VideoRendererImpl::Paint(SkCanvas* canvas, const gfx::Rect& dest_rect) { ...@@ -64,13 +59,6 @@ void VideoRendererImpl::Paint(SkCanvas* canvas, const gfx::Rect& dest_rect) {
} else { } else {
SlowPaint(video_frame, canvas, dest_rect); SlowPaint(video_frame, canvas, dest_rect);
} }
// Presentation timestamp logging is primarily used to measure performance
// on low-end devices. When profiled on an Intel Atom N280 @ 1.66GHz this
// code had a ~63 microsecond perf hit when logging to a file (not stdout),
// which is neglible enough for measuring playback performance.
if (pts_logging_)
VLOG(1) << "pts=" << video_frame->GetTimestamp().InMicroseconds();
} }
PutCurrentFrame(video_frame); PutCurrentFrame(video_frame);
......
...@@ -9,25 +9,30 @@ ...@@ -9,25 +9,30 @@
#include "media/base/filters.h" #include "media/base/filters.h"
#include "media/filters/video_renderer_base.h" #include "media/filters/video_renderer_base.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebMediaPlayer.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebMediaPlayer.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/size.h" #include "ui/gfx/size.h"
#include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkBitmap.h"
#include "webkit/media/web_video_renderer.h"
class SkCanvas;
namespace webkit_media { namespace webkit_media {
class WebMediaPlayerProxy;
// The video renderer implementation to be use by the media pipeline. It lives // The video renderer implementation to be use by the media pipeline. It lives
// inside video renderer thread and also WebKit's main thread. We need to be // inside video renderer thread and also WebKit's main thread. We need to be
// extra careful about members shared by two different threads, especially // extra careful about members shared by two different threads, especially
// video frame buffers. // video frame buffers.
class VideoRendererImpl : public WebVideoRenderer { class VideoRendererImpl : public media::VideoRendererBase {
public: public:
explicit VideoRendererImpl(bool pts_logging); explicit VideoRendererImpl(const scoped_refptr<WebMediaPlayerProxy>& proxy);
virtual ~VideoRendererImpl(); virtual ~VideoRendererImpl();
// WebVideoRenderer implementation. // Paint the current front frame on the |canvas| stretching it to fit the
virtual void SetWebMediaPlayerProxy(WebMediaPlayerProxy* proxy) OVERRIDE; // |dest_rect|.
virtual void SetRect(const gfx::Rect& rect) OVERRIDE; //
virtual void Paint(SkCanvas* canvas, const gfx::Rect& dest_rect) OVERRIDE; // Method called on the render thread.
void Paint(SkCanvas* canvas, const gfx::Rect& dest_rect);
protected: protected:
// VideoRendererBase implementation. // VideoRendererBase implementation.
...@@ -71,9 +76,6 @@ class VideoRendererImpl : public WebVideoRenderer { ...@@ -71,9 +76,6 @@ class VideoRendererImpl : public WebVideoRenderer {
// The natural size of the video. // The natural size of the video.
gfx::Size natural_size_; gfx::Size natural_size_;
// Whether we're logging video presentation timestamps (PTS).
bool pts_logging_;
DISALLOW_COPY_AND_ASSIGN(VideoRendererImpl); DISALLOW_COPY_AND_ASSIGN(VideoRendererImpl);
}; };
......
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef WEBKIT_MEDIA_WEB_VIDEO_RENDERER_H_
#define WEBKIT_MEDIA_WEB_VIDEO_RENDERER_H_
#include "media/base/video_frame.h"
#include "media/filters/video_renderer_base.h"
#include "ui/gfx/rect.h"
class SkCanvas;
namespace webkit_media {
class WebMediaPlayerProxy;
// A specialized version of a VideoRenderer designed to be used inside WebKit.
class WebVideoRenderer : public media::VideoRendererBase {
public:
WebVideoRenderer() : media::VideoRendererBase() {}
virtual ~WebVideoRenderer() {}
// Saves the reference to WebMediaPlayerProxy.
virtual void SetWebMediaPlayerProxy(WebMediaPlayerProxy* proxy) = 0;
// This method is called with the same rect as the Paint() method and could
// be used by future implementations to implement an improved color space +
// scale code on a separate thread. Since we always do the stretch on the
// same thread as the Paint method, we just ignore the call for now.
//
// Method called on the render thread.
virtual void SetRect(const gfx::Rect& rect) = 0;
// Paint the current front frame on the |canvas| stretching it to fit the
// |dest_rect|.
//
// Method called on the render thread.
virtual void Paint(SkCanvas* canvas, const gfx::Rect& dest_rect) = 0;
private:
DISALLOW_COPY_AND_ASSIGN(WebVideoRenderer);
};
} // namespace webkit_media
#endif // WEBKIT_MEDIA_WEB_VIDEO_RENDERER_H_
...@@ -29,7 +29,6 @@ ...@@ -29,7 +29,6 @@
'web_data_source_factory.cc', 'web_data_source_factory.cc',
'web_data_source_factory.h', 'web_data_source_factory.h',
'web_data_source.h', 'web_data_source.h',
'web_video_renderer.h',
'webmediaplayer_delegate.h', 'webmediaplayer_delegate.h',
'webmediaplayer_impl.cc', 'webmediaplayer_impl.cc',
'webmediaplayer_impl.h', 'webmediaplayer_impl.h',
......
...@@ -34,7 +34,6 @@ ...@@ -34,7 +34,6 @@
#include "webkit/media/media_stream_client.h" #include "webkit/media/media_stream_client.h"
#include "webkit/media/simple_data_source.h" #include "webkit/media/simple_data_source.h"
#include "webkit/media/video_renderer_impl.h" #include "webkit/media/video_renderer_impl.h"
#include "webkit/media/web_video_renderer.h"
#include "webkit/media/webmediaplayer_delegate.h" #include "webkit/media/webmediaplayer_delegate.h"
#include "webkit/media/webmediaplayer_proxy.h" #include "webkit/media/webmediaplayer_proxy.h"
#include "webkit/media/webvideoframe_impl.h" #include "webkit/media/webvideoframe_impl.h"
...@@ -132,8 +131,7 @@ WebMediaPlayerImpl::WebMediaPlayerImpl( ...@@ -132,8 +131,7 @@ WebMediaPlayerImpl::WebMediaPlayerImpl(
bool WebMediaPlayerImpl::Initialize( bool WebMediaPlayerImpl::Initialize(
WebKit::WebFrame* frame, WebKit::WebFrame* frame,
bool use_simple_data_source, bool use_simple_data_source) {
scoped_refptr<WebVideoRenderer> web_video_renderer) {
DCHECK_EQ(main_loop_, MessageLoop::current()); DCHECK_EQ(main_loop_, MessageLoop::current());
MessageLoop* pipeline_message_loop = MessageLoop* pipeline_message_loop =
message_loop_factory_->GetMessageLoop("PipelineThread"); message_loop_factory_->GetMessageLoop("PipelineThread");
...@@ -162,10 +160,12 @@ bool WebMediaPlayerImpl::Initialize( ...@@ -162,10 +160,12 @@ bool WebMediaPlayerImpl::Initialize(
// Also we want to be notified of |main_loop_| destruction. // Also we want to be notified of |main_loop_| destruction.
main_loop_->AddDestructionObserver(this); main_loop_->AddDestructionObserver(this);
// Creates the proxy. // Create proxy and default video renderer.
proxy_ = new WebMediaPlayerProxy(main_loop_, this); proxy_ = new WebMediaPlayerProxy(main_loop_, this);
web_video_renderer->SetWebMediaPlayerProxy(proxy_); scoped_refptr<VideoRendererImpl> video_renderer =
proxy_->SetVideoRenderer(web_video_renderer); new VideoRendererImpl(proxy_);
filter_collection_->AddVideoRenderer(video_renderer);
proxy_->SetVideoRenderer(video_renderer);
// Set our pipeline callbacks. // Set our pipeline callbacks.
pipeline_->Init( pipeline_->Init(
...@@ -560,9 +560,8 @@ unsigned long long WebMediaPlayerImpl::totalBytes() const { ...@@ -560,9 +560,8 @@ unsigned long long WebMediaPlayerImpl::totalBytes() const {
void WebMediaPlayerImpl::setSize(const WebSize& size) { void WebMediaPlayerImpl::setSize(const WebSize& size) {
DCHECK_EQ(main_loop_, MessageLoop::current()); DCHECK_EQ(main_loop_, MessageLoop::current());
DCHECK(proxy_);
proxy_->SetSize(gfx::Rect(0, 0, size.width, size.height)); // Don't need to do anything as we use the dimensions passed in via paint().
} }
void WebMediaPlayerImpl::paint(WebCanvas* canvas, void WebMediaPlayerImpl::paint(WebCanvas* canvas,
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
// media::PipelineImpl // media::PipelineImpl
// The media playback pipeline. // The media playback pipeline.
// //
// WebVideoRenderer // VideoRendererImpl
// Video renderer object. // Video renderer object.
// //
// WebKit::WebMediaPlayerClient // WebKit::WebMediaPlayerClient
...@@ -29,12 +29,12 @@ ...@@ -29,12 +29,12 @@
// WebMediaPlayerImpl ---> PipelineImpl // WebMediaPlayerImpl ---> PipelineImpl
// | ^ | // | ^ |
// | | v r // | | v r
// | | WebVideoRenderer // | | VideoRendererImpl
// | | | ^ r // | | | ^ r
// | r | v r | // | r | v r |
// '---> WebMediaPlayerProxy --' // '---> WebMediaPlayerProxy --'
// //
// Notice that WebMediaPlayerProxy and WebVideoRenderer are referencing each // Notice that WebMediaPlayerProxy and VideoRendererImpl are referencing each
// other. This interdependency has to be treated carefully. // other. This interdependency has to be treated carefully.
// //
// Other issues: // Other issues:
...@@ -72,7 +72,6 @@ namespace webkit_media { ...@@ -72,7 +72,6 @@ namespace webkit_media {
class MediaStreamClient; class MediaStreamClient;
class WebMediaPlayerDelegate; class WebMediaPlayerDelegate;
class WebMediaPlayerProxy; class WebMediaPlayerProxy;
class WebVideoRenderer;
class WebMediaPlayerImpl class WebMediaPlayerImpl
: public WebKit::WebMediaPlayer, : public WebKit::WebMediaPlayer,
...@@ -110,10 +109,7 @@ class WebMediaPlayerImpl ...@@ -110,10 +109,7 @@ class WebMediaPlayerImpl
virtual ~WebMediaPlayerImpl(); virtual ~WebMediaPlayerImpl();
// Finalizes initialization of the object. // Finalizes initialization of the object.
bool Initialize( bool Initialize(WebKit::WebFrame* frame, bool use_simple_data_source);
WebKit::WebFrame* frame,
bool use_simple_data_source,
scoped_refptr<WebVideoRenderer> web_video_renderer);
virtual void load(const WebKit::WebURL& url); virtual void load(const WebKit::WebURL& url);
virtual void cancelLoad(); virtual void cancelLoad();
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
#include "base/message_loop.h" #include "base/message_loop.h"
#include "media/base/pipeline_status.h" #include "media/base/pipeline_status.h"
#include "media/filters/chunk_demuxer.h" #include "media/filters/chunk_demuxer.h"
#include "webkit/media/web_video_renderer.h" #include "webkit/media/video_renderer_impl.h"
#include "webkit/media/webmediaplayer_impl.h" #include "webkit/media/webmediaplayer_impl.h"
using media::NetworkEvent; using media::NetworkEvent;
...@@ -46,7 +46,7 @@ void WebMediaPlayerProxy::Repaint() { ...@@ -46,7 +46,7 @@ void WebMediaPlayerProxy::Repaint() {
} }
void WebMediaPlayerProxy::SetVideoRenderer( void WebMediaPlayerProxy::SetVideoRenderer(
scoped_refptr<WebVideoRenderer> video_renderer) { const scoped_refptr<VideoRendererImpl>& video_renderer) {
video_renderer_ = video_renderer; video_renderer_ = video_renderer;
} }
...@@ -61,13 +61,6 @@ void WebMediaPlayerProxy::Paint(SkCanvas* canvas, const gfx::Rect& dest_rect) { ...@@ -61,13 +61,6 @@ void WebMediaPlayerProxy::Paint(SkCanvas* canvas, const gfx::Rect& dest_rect) {
} }
} }
void WebMediaPlayerProxy::SetSize(const gfx::Rect& rect) {
DCHECK(MessageLoop::current() == render_loop_);
if (video_renderer_) {
video_renderer_->SetRect(rect);
}
}
bool WebMediaPlayerProxy::HasSingleOrigin() { bool WebMediaPlayerProxy::HasSingleOrigin() {
DCHECK(MessageLoop::current() == render_loop_); DCHECK(MessageLoop::current() == render_loop_);
......
...@@ -23,7 +23,7 @@ class Rect; ...@@ -23,7 +23,7 @@ class Rect;
namespace webkit_media { namespace webkit_media {
class WebMediaPlayerImpl; class WebMediaPlayerImpl;
class WebVideoRenderer; class VideoRendererImpl;
// Acts as a thread proxy between the various threads used for multimedia and // Acts as a thread proxy between the various threads used for multimedia and
// the render thread that WebMediaPlayerImpl is running on. // the render thread that WebMediaPlayerImpl is running on.
...@@ -36,12 +36,11 @@ class WebMediaPlayerProxy ...@@ -36,12 +36,11 @@ class WebMediaPlayerProxy
// Methods for Filter -> WebMediaPlayerImpl communication. // Methods for Filter -> WebMediaPlayerImpl communication.
void Repaint(); void Repaint();
void SetVideoRenderer(scoped_refptr<WebVideoRenderer> video_renderer); void SetVideoRenderer(const scoped_refptr<VideoRendererImpl>& video_renderer);
WebDataSourceBuildObserverHack GetBuildObserver(); WebDataSourceBuildObserverHack GetBuildObserver();
// Methods for WebMediaPlayerImpl -> Filter communication. // Methods for WebMediaPlayerImpl -> Filter communication.
void Paint(SkCanvas* canvas, const gfx::Rect& dest_rect); void Paint(SkCanvas* canvas, const gfx::Rect& dest_rect);
void SetSize(const gfx::Rect& rect);
void Detach(); void Detach();
void GetCurrentFrame(scoped_refptr<media::VideoFrame>* frame_out); void GetCurrentFrame(scoped_refptr<media::VideoFrame>* frame_out);
void PutCurrentFrame(scoped_refptr<media::VideoFrame> frame); void PutCurrentFrame(scoped_refptr<media::VideoFrame> frame);
...@@ -105,7 +104,7 @@ class WebMediaPlayerProxy ...@@ -105,7 +104,7 @@ class WebMediaPlayerProxy
typedef std::list<scoped_refptr<WebDataSource> > DataSourceList; typedef std::list<scoped_refptr<WebDataSource> > DataSourceList;
DataSourceList data_sources_; DataSourceList data_sources_;
scoped_refptr<WebVideoRenderer> video_renderer_; scoped_refptr<VideoRendererImpl> video_renderer_;
base::Lock lock_; base::Lock lock_;
int outstanding_repaints_; int outstanding_repaints_;
......
...@@ -318,10 +318,6 @@ WebKit::WebMediaPlayer* CreateMediaPlayer(WebFrame* frame, ...@@ -318,10 +318,6 @@ WebKit::WebMediaPlayer* CreateMediaPlayer(WebFrame* frame,
scoped_ptr<media::FilterCollection> collection( scoped_ptr<media::FilterCollection> collection(
new media::FilterCollection()); new media::FilterCollection());
scoped_refptr<webkit_media::VideoRendererImpl> video_renderer(
new webkit_media::VideoRendererImpl(false));
collection->AddVideoRenderer(video_renderer);
scoped_ptr<webkit_media::WebMediaPlayerImpl> result( scoped_ptr<webkit_media::WebMediaPlayerImpl> result(
new webkit_media::WebMediaPlayerImpl( new webkit_media::WebMediaPlayerImpl(
client, client,
...@@ -330,7 +326,7 @@ WebKit::WebMediaPlayer* CreateMediaPlayer(WebFrame* frame, ...@@ -330,7 +326,7 @@ WebKit::WebMediaPlayer* CreateMediaPlayer(WebFrame* frame,
message_loop_factory.release(), message_loop_factory.release(),
NULL, NULL,
new media::MediaLog())); new media::MediaLog()));
if (!result->Initialize(frame, false, video_renderer)) { if (!result->Initialize(frame, false)) {
return NULL; return NULL;
} }
return result.release(); return result.release();
......
...@@ -647,10 +647,6 @@ WebMediaPlayer* TestWebViewDelegate::createMediaPlayer( ...@@ -647,10 +647,6 @@ WebMediaPlayer* TestWebViewDelegate::createMediaPlayer(
scoped_ptr<media::FilterCollection> collection( scoped_ptr<media::FilterCollection> collection(
new media::FilterCollection()); new media::FilterCollection());
scoped_refptr<webkit_media::VideoRendererImpl> video_renderer(
new webkit_media::VideoRendererImpl(false));
collection->AddVideoRenderer(video_renderer);
scoped_ptr<webkit_media::WebMediaPlayerImpl> result( scoped_ptr<webkit_media::WebMediaPlayerImpl> result(
new webkit_media::WebMediaPlayerImpl( new webkit_media::WebMediaPlayerImpl(
client, client,
...@@ -659,7 +655,7 @@ WebMediaPlayer* TestWebViewDelegate::createMediaPlayer( ...@@ -659,7 +655,7 @@ WebMediaPlayer* TestWebViewDelegate::createMediaPlayer(
message_loop_factory.release(), message_loop_factory.release(),
NULL, NULL,
new media::MediaLog())); new media::MediaLog()));
if (!result->Initialize(frame, false, video_renderer)) { if (!result->Initialize(frame, false)) {
return NULL; return NULL;
} }
return result.release(); return result.release();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment