cricket::VideoFrameFactory: Don't overwrite frames in use

VideoFrameFactory has a single frame buffer that is used when scaling frames. If the previous frame is still in use, we need to allocate a new frame.

BUG=4347
R=perkj@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/36359004

Cr-Commit-Position: refs/heads/master@{#8549}
git-svn-id: http://webrtc.googlecode.com/svn/trunk@8549 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/talk/media/base/videoframe.h b/talk/media/base/videoframe.h
index 56621ad..2e9a01b 100644
--- a/talk/media/base/videoframe.h
+++ b/talk/media/base/videoframe.h
@@ -132,9 +132,14 @@
   virtual VideoFrame *Copy() const = 0;
 
   // Since VideoFrame supports shallow copy and the internal frame buffer might
-  // be shared, in case VideoFrame needs exclusive access of the frame buffer,
-  // user can call MakeExclusive() to make sure the frame buffer is exclusive
-  // accessable to the current object.  This might mean a deep copy of the frame
+  // be shared, this function can be used to check exclusive ownership. The
+  // default implementation is conservative and returns false. Subclasses with
+  // knowledge of implementation specific details can override this.
+  virtual bool IsExclusive() const { return false; }
+
+  // In case VideoFrame needs exclusive access of the frame buffer, user can
+  // call MakeExclusive() to make sure the frame buffer is exclusively
+  // accessible to the current object.  This might mean a deep copy of the frame
   // buffer if it is currently shared by other objects.
   virtual bool MakeExclusive() = 0;
 
diff --git a/talk/media/base/videoframefactory.cc b/talk/media/base/videoframefactory.cc
index b4725cd..147f1fa 100644
--- a/talk/media/base/videoframefactory.cc
+++ b/talk/media/base/videoframefactory.cc
@@ -46,9 +46,9 @@
     return cropped_input_frame.release();
   }
 
-  // Create and stretch the output frame if it has not been created yet or its
-  // size is not same as the expected.
-  if (!output_frame_ ||
+  // Create and stretch the output frame if it has not been created yet, is
+  // still in use by others, or its size is not same as the expected.
+  if (!output_frame_ || !output_frame_->IsExclusive() ||
       output_frame_->GetWidth() != static_cast<size_t>(output_width) ||
       output_frame_->GetHeight() != static_cast<size_t>(output_height)) {
     output_frame_.reset(
diff --git a/talk/media/webrtc/webrtcvideoframe.cc b/talk/media/webrtc/webrtcvideoframe.cc
index 9764f31..0b1d4a8 100644
--- a/talk/media/webrtc/webrtcvideoframe.cc
+++ b/talk/media/webrtc/webrtcvideoframe.cc
@@ -244,7 +244,15 @@
   return ret_val;
 }
 
+bool WebRtcVideoFrame::IsExclusive() const {
+  return video_buffer_->HasOneRef();
+}
+
 bool WebRtcVideoFrame::MakeExclusive() {
+  if (IsExclusive())
+    return true;
+
+  // Not exclusive already, need to copy.
   const size_t length = video_buffer_->length();
   RefCountedBuffer* exclusive_buffer = new RefCountedBuffer(length);
   memcpy(exclusive_buffer->data(), video_buffer_->data(), length);
diff --git a/talk/media/webrtc/webrtcvideoframe.h b/talk/media/webrtc/webrtcvideoframe.h
index 4de12b2..2e34d67 100644
--- a/talk/media/webrtc/webrtcvideoframe.h
+++ b/talk/media/webrtc/webrtcvideoframe.h
@@ -137,6 +137,7 @@
   }
 
   virtual VideoFrame* Copy() const;
+  virtual bool IsExclusive() const;
   virtual bool MakeExclusive();
   virtual size_t ConvertToRgbBuffer(uint32 to_fourcc, uint8* buffer,
                                     size_t size, int stride_rgb) const;