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 17namespace { 18// An implementation of EncodedImageBufferInterface that doesn't perform any copies. 19class ObjCEncodedImageBuffer : public webrtc::EncodedImageBufferInterface { 20 public: 21 static rtc::scoped_refptr<ObjCEncodedImageBuffer> Create(NSData *data) { 22 return rtc::make_ref_counted<ObjCEncodedImageBuffer>(data); 23 } 24 const uint8_t *data() const override { return static_cast<const uint8_t *>(data_.bytes); } 25 // TODO(bugs.webrtc.org/9378): delete this non-const data method. 26 uint8_t *data() override { 27 return const_cast<uint8_t *>(static_cast<const uint8_t *>(data_.bytes)); 28 } 29 size_t size() const override { return data_.length; } 30 31 protected: 32 explicit ObjCEncodedImageBuffer(NSData *data) : data_(data) {} 33 ~ObjCEncodedImageBuffer() {} 34 35 NSData *data_; 36}; 37} 38 39// A simple wrapper around webrtc::EncodedImageBufferInterface to make it usable with associated 40// objects. 41@interface RTCWrappedEncodedImageBuffer : NSObject 42@property(nonatomic) rtc::scoped_refptr<webrtc::EncodedImageBufferInterface> buffer; 43- (instancetype)initWithEncodedImageBuffer: 44 (rtc::scoped_refptr<webrtc::EncodedImageBufferInterface>)buffer; 45@end 46@implementation RTCWrappedEncodedImageBuffer 47@synthesize buffer = _buffer; 48- (instancetype)initWithEncodedImageBuffer: 49 (rtc::scoped_refptr<webrtc::EncodedImageBufferInterface>)buffer { 50 self = [super init]; 51 if (self) { 52 _buffer = buffer; 53 } 54 return self; 55} 56@end 57 58@implementation RTC_OBJC_TYPE (RTCEncodedImage) 59(Private) 60 61 - (rtc::scoped_refptr<webrtc::EncodedImageBufferInterface>)encodedData { 62 RTCWrappedEncodedImageBuffer *wrappedBuffer = 63 objc_getAssociatedObject(self, @selector(encodedData)); 64 return wrappedBuffer.buffer; 65} 66 67- (void)setEncodedData:(rtc::scoped_refptr<webrtc::EncodedImageBufferInterface>)buffer { 68 return objc_setAssociatedObject( 69 self, 70 @selector(encodedData), 71 [[RTCWrappedEncodedImageBuffer alloc] initWithEncodedImageBuffer:buffer], 72 OBJC_ASSOCIATION_RETAIN_NONATOMIC); 73} 74 75- (instancetype)initWithNativeEncodedImage:(const webrtc::EncodedImage &)encodedImage { 76 if (self = [super init]) { 77 // A reference to the encodedData must be stored so that it's kept alive as long 78 // self.buffer references its underlying data. 79 self.encodedData = encodedImage.GetEncodedData(); 80 // Wrap the buffer in NSData without copying, do not take ownership. 81 self.buffer = [NSData dataWithBytesNoCopy:self.encodedData->data() 82 length:encodedImage.size() 83 freeWhenDone:NO]; 84 self.encodedWidth = rtc::dchecked_cast<int32_t>(encodedImage._encodedWidth); 85 self.encodedHeight = rtc::dchecked_cast<int32_t>(encodedImage._encodedHeight); 86 self.timeStamp = encodedImage.Timestamp(); 87 self.captureTimeMs = encodedImage.capture_time_ms_; 88 self.ntpTimeMs = encodedImage.ntp_time_ms_; 89 self.flags = encodedImage.timing_.flags; 90 self.encodeStartMs = encodedImage.timing_.encode_start_ms; 91 self.encodeFinishMs = encodedImage.timing_.encode_finish_ms; 92 self.frameType = static_cast<RTCFrameType>(encodedImage._frameType); 93 self.rotation = static_cast<RTCVideoRotation>(encodedImage.rotation_); 94 self.qp = @(encodedImage.qp_); 95 self.contentType = (encodedImage.content_type_ == webrtc::VideoContentType::SCREENSHARE) ? 96 RTCVideoContentTypeScreenshare : 97 RTCVideoContentTypeUnspecified; 98 } 99 100 return self; 101} 102 103- (webrtc::EncodedImage)nativeEncodedImage { 104 // Return the pointer without copying. 105 webrtc::EncodedImage encodedImage; 106 if (self.encodedData) { 107 encodedImage.SetEncodedData(self.encodedData); 108 } else if (self.buffer) { 109 encodedImage.SetEncodedData(ObjCEncodedImageBuffer::Create(self.buffer)); 110 } 111 encodedImage.set_size(self.buffer.length); 112 encodedImage._encodedWidth = rtc::dchecked_cast<uint32_t>(self.encodedWidth); 113 encodedImage._encodedHeight = rtc::dchecked_cast<uint32_t>(self.encodedHeight); 114 encodedImage.SetTimestamp(self.timeStamp); 115 encodedImage.capture_time_ms_ = self.captureTimeMs; 116 encodedImage.ntp_time_ms_ = self.ntpTimeMs; 117 encodedImage.timing_.flags = self.flags; 118 encodedImage.timing_.encode_start_ms = self.encodeStartMs; 119 encodedImage.timing_.encode_finish_ms = self.encodeFinishMs; 120 encodedImage._frameType = webrtc::VideoFrameType(self.frameType); 121 encodedImage.rotation_ = webrtc::VideoRotation(self.rotation); 122 encodedImage.qp_ = self.qp ? self.qp.intValue : -1; 123 encodedImage.content_type_ = (self.contentType == RTCVideoContentTypeScreenshare) ? 124 webrtc::VideoContentType::SCREENSHARE : 125 webrtc::VideoContentType::UNSPECIFIED; 126 127 return encodedImage; 128} 129 130@end 131