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