• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 *  Copyright 2017 The WebRTC project authors. All Rights Reserved.
3 *
4 *  Use of this source code is governed by a BSD-style license
5 *  that can be found in the LICENSE file in the root of the source
6 *  tree. An additional intellectual property rights grant can be found
7 *  in the file PATENTS.  All contributing project authors may
8 *  be found in the AUTHORS file in the root of the source tree.
9 */
10
11#import "RTCEncodedImage+Private.h"
12
13#import <objc/runtime.h>
14
15#include "rtc_base/numerics/safe_conversions.h"
16#include "rtc_base/ref_counted_object.h"
17
18namespace {
19// An implementation of EncodedImageBufferInterface that doesn't perform any copies.
20class ObjCEncodedImageBuffer : public webrtc::EncodedImageBufferInterface {
21 public:
22  static rtc::scoped_refptr<ObjCEncodedImageBuffer> Create(NSData *data) {
23    return new rtc::RefCountedObject<ObjCEncodedImageBuffer>(data);
24  }
25  const uint8_t *data() const override { return static_cast<const uint8_t *>(data_.bytes); }
26  // TODO(bugs.webrtc.org/9378): delete this non-const data method.
27  uint8_t *data() override {
28    return const_cast<uint8_t *>(static_cast<const uint8_t *>(data_.bytes));
29  }
30  size_t size() const override { return data_.length; }
31
32 protected:
33  explicit ObjCEncodedImageBuffer(NSData *data) : data_(data) {}
34  ~ObjCEncodedImageBuffer() {}
35
36  NSData *data_;
37};
38}
39
40// A simple wrapper around webrtc::EncodedImageBufferInterface to make it usable with associated
41// objects.
42@interface RTCWrappedEncodedImageBuffer : NSObject
43@property(nonatomic) rtc::scoped_refptr<webrtc::EncodedImageBufferInterface> buffer;
44- (instancetype)initWithEncodedImageBuffer:
45    (rtc::scoped_refptr<webrtc::EncodedImageBufferInterface>)buffer;
46@end
47@implementation RTCWrappedEncodedImageBuffer
48@synthesize buffer = _buffer;
49- (instancetype)initWithEncodedImageBuffer:
50    (rtc::scoped_refptr<webrtc::EncodedImageBufferInterface>)buffer {
51  self = [super init];
52  if (self) {
53    _buffer = buffer;
54  }
55  return self;
56}
57@end
58
59@implementation RTC_OBJC_TYPE (RTCEncodedImage)
60(Private)
61
62    - (rtc::scoped_refptr<webrtc::EncodedImageBufferInterface>)encodedData {
63  RTCWrappedEncodedImageBuffer *wrappedBuffer =
64      objc_getAssociatedObject(self, @selector(encodedData));
65  return wrappedBuffer.buffer;
66}
67
68- (void)setEncodedData:(rtc::scoped_refptr<webrtc::EncodedImageBufferInterface>)buffer {
69  return objc_setAssociatedObject(
70      self,
71      @selector(encodedData),
72      [[RTCWrappedEncodedImageBuffer alloc] initWithEncodedImageBuffer:buffer],
73      OBJC_ASSOCIATION_RETAIN_NONATOMIC);
74}
75
76- (instancetype)initWithNativeEncodedImage:(const webrtc::EncodedImage &)encodedImage {
77  if (self = [super init]) {
78    // A reference to the encodedData must be stored so that it's kept alive as long
79    // self.buffer references its underlying data.
80    self.encodedData = encodedImage.GetEncodedData();
81    // Wrap the buffer in NSData without copying, do not take ownership.
82    self.buffer = [NSData dataWithBytesNoCopy:self.encodedData->data()
83                                       length:encodedImage.size()
84                                 freeWhenDone:NO];
85    self.encodedWidth = rtc::dchecked_cast<int32_t>(encodedImage._encodedWidth);
86    self.encodedHeight = rtc::dchecked_cast<int32_t>(encodedImage._encodedHeight);
87    self.timeStamp = encodedImage.Timestamp();
88    self.captureTimeMs = encodedImage.capture_time_ms_;
89    self.ntpTimeMs = encodedImage.ntp_time_ms_;
90    self.flags = encodedImage.timing_.flags;
91    self.encodeStartMs = encodedImage.timing_.encode_start_ms;
92    self.encodeFinishMs = encodedImage.timing_.encode_finish_ms;
93    self.frameType = static_cast<RTCFrameType>(encodedImage._frameType);
94    self.rotation = static_cast<RTCVideoRotation>(encodedImage.rotation_);
95    self.completeFrame = encodedImage._completeFrame;
96    self.qp = @(encodedImage.qp_);
97    self.contentType = (encodedImage.content_type_ == webrtc::VideoContentType::SCREENSHARE) ?
98        RTCVideoContentTypeScreenshare :
99        RTCVideoContentTypeUnspecified;
100  }
101
102  return self;
103}
104
105- (webrtc::EncodedImage)nativeEncodedImage {
106  // Return the pointer without copying.
107  webrtc::EncodedImage encodedImage;
108  if (self.encodedData) {
109    encodedImage.SetEncodedData(self.encodedData);
110  } else if (self.buffer) {
111    encodedImage.SetEncodedData(ObjCEncodedImageBuffer::Create(self.buffer));
112  }
113  encodedImage.set_size(self.buffer.length);
114  encodedImage._encodedWidth = rtc::dchecked_cast<uint32_t>(self.encodedWidth);
115  encodedImage._encodedHeight = rtc::dchecked_cast<uint32_t>(self.encodedHeight);
116  encodedImage.SetTimestamp(self.timeStamp);
117  encodedImage.capture_time_ms_ = self.captureTimeMs;
118  encodedImage.ntp_time_ms_ = self.ntpTimeMs;
119  encodedImage.timing_.flags = self.flags;
120  encodedImage.timing_.encode_start_ms = self.encodeStartMs;
121  encodedImage.timing_.encode_finish_ms = self.encodeFinishMs;
122  encodedImage._frameType = webrtc::VideoFrameType(self.frameType);
123  encodedImage.rotation_ = webrtc::VideoRotation(self.rotation);
124  encodedImage._completeFrame = self.completeFrame;
125  encodedImage.qp_ = self.qp ? self.qp.intValue : -1;
126  encodedImage.content_type_ = (self.contentType == RTCVideoContentTypeScreenshare) ?
127      webrtc::VideoContentType::SCREENSHARE :
128      webrtc::VideoContentType::UNSPECIFIED;
129
130  return encodedImage;
131}
132
133@end
134