Anders Carlsson | 7bca8ca | 2018-08-30 09:30:29 +0200 | [diff] [blame] | 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 | |
Kári Tristan Helgason | 03e85d2 | 2019-04-25 08:57:41 +0200 | [diff] [blame] | 13 | #import <objc/runtime.h> |
| 14 | |
Anders Carlsson | 7bca8ca | 2018-08-30 09:30:29 +0200 | [diff] [blame] | 15 | #include "rtc_base/numerics/safe_conversions.h" |
Kári Tristan Helgason | ecbdbf6 | 2020-02-20 07:34:45 -0800 | [diff] [blame] | 16 | |
| 17 | namespace { |
| 18 | // An implementation of EncodedImageBufferInterface that doesn't perform any copies. |
| 19 | class ObjCEncodedImageBuffer : public webrtc::EncodedImageBufferInterface { |
| 20 | public: |
| 21 | static rtc::scoped_refptr<ObjCEncodedImageBuffer> Create(NSData *data) { |
Niels Möller | ac0d183 | 2022-01-17 15:26:54 +0100 | [diff] [blame] | 22 | return rtc::make_ref_counted<ObjCEncodedImageBuffer>(data); |
Kári Tristan Helgason | ecbdbf6 | 2020-02-20 07:34:45 -0800 | [diff] [blame] | 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 | } |
Anders Carlsson | 7bca8ca | 2018-08-30 09:30:29 +0200 | [diff] [blame] | 38 | |
Niels Möller | 4d504c7 | 2019-06-18 15:56:56 +0200 | [diff] [blame] | 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; |
Kári Tristan Helgason | 03e85d2 | 2019-04-25 08:57:41 +0200 | [diff] [blame] | 45 | @end |
Niels Möller | 4d504c7 | 2019-06-18 15:56:56 +0200 | [diff] [blame] | 46 | @implementation RTCWrappedEncodedImageBuffer |
Kári Tristan Helgason | 03e85d2 | 2019-04-25 08:57:41 +0200 | [diff] [blame] | 47 | @synthesize buffer = _buffer; |
Niels Möller | 4d504c7 | 2019-06-18 15:56:56 +0200 | [diff] [blame] | 48 | - (instancetype)initWithEncodedImageBuffer: |
| 49 | (rtc::scoped_refptr<webrtc::EncodedImageBufferInterface>)buffer { |
Kári Tristan Helgason | 03e85d2 | 2019-04-25 08:57:41 +0200 | [diff] [blame] | 50 | self = [super init]; |
| 51 | if (self) { |
| 52 | _buffer = buffer; |
| 53 | } |
| 54 | return self; |
| 55 | } |
| 56 | @end |
| 57 | |
Mirko Bonadei | a81e9c8 | 2020-05-04 16:14:32 +0200 | [diff] [blame] | 58 | @implementation RTC_OBJC_TYPE (RTCEncodedImage) |
| 59 | (Private) |
Anders Carlsson | 7bca8ca | 2018-08-30 09:30:29 +0200 | [diff] [blame] | 60 | |
Mirko Bonadei | a81e9c8 | 2020-05-04 16:14:32 +0200 | [diff] [blame] | 61 | - (rtc::scoped_refptr<webrtc::EncodedImageBufferInterface>)encodedData { |
Niels Möller | 4d504c7 | 2019-06-18 15:56:56 +0200 | [diff] [blame] | 62 | RTCWrappedEncodedImageBuffer *wrappedBuffer = |
| 63 | objc_getAssociatedObject(self, @selector(encodedData)); |
Kári Tristan Helgason | 03e85d2 | 2019-04-25 08:57:41 +0200 | [diff] [blame] | 64 | return wrappedBuffer.buffer; |
| 65 | } |
| 66 | |
Niels Möller | 4d504c7 | 2019-06-18 15:56:56 +0200 | [diff] [blame] | 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); |
Kári Tristan Helgason | 03e85d2 | 2019-04-25 08:57:41 +0200 | [diff] [blame] | 73 | } |
| 74 | |
Dillon Cower | 5963fdd | 2019-02-07 16:17:43 -0800 | [diff] [blame] | 75 | - (instancetype)initWithNativeEncodedImage:(const webrtc::EncodedImage &)encodedImage { |
Anders Carlsson | 7bca8ca | 2018-08-30 09:30:29 +0200 | [diff] [blame] | 76 | if (self = [super init]) { |
Kári Tristan Helgason | ecbdbf6 | 2020-02-20 07:34:45 -0800 | [diff] [blame] | 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(); |
Anders Carlsson | 7bca8ca | 2018-08-30 09:30:29 +0200 | [diff] [blame] | 80 | // Wrap the buffer in NSData without copying, do not take ownership. |
Kári Tristan Helgason | ecbdbf6 | 2020-02-20 07:34:45 -0800 | [diff] [blame] | 81 | self.buffer = [NSData dataWithBytesNoCopy:self.encodedData->data() |
Kári Tristan Helgason | ba9e1b8 | 2020-03-16 16:49:11 +0100 | [diff] [blame] | 82 | length:encodedImage.size() |
Niels Möller | 77536a2 | 2019-01-15 08:50:01 +0100 | [diff] [blame] | 83 | freeWhenDone:NO]; |
Anders Carlsson | 7bca8ca | 2018-08-30 09:30:29 +0200 | [diff] [blame] | 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_); |
Anders Carlsson | 7bca8ca | 2018-08-30 09:30:29 +0200 | [diff] [blame] | 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. |
Kári Tristan Helgason | ecbdbf6 | 2020-02-20 07:34:45 -0800 | [diff] [blame] | 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); |
Anders Carlsson | 7bca8ca | 2018-08-30 09:30:29 +0200 | [diff] [blame] | 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; |
Niels Möller | 87e2d78 | 2019-03-07 10:18:23 +0100 | [diff] [blame] | 120 | encodedImage._frameType = webrtc::VideoFrameType(self.frameType); |
Anders Carlsson | 7bca8ca | 2018-08-30 09:30:29 +0200 | [diff] [blame] | 121 | encodedImage.rotation_ = webrtc::VideoRotation(self.rotation); |
Anders Carlsson | 7bca8ca | 2018-08-30 09:30:29 +0200 | [diff] [blame] | 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 |