blob: b3e0a7bb677fb3326cdf205d8e6bed569423048e [file] [log] [blame]
Anders Carlsson7bca8ca2018-08-30 09:30:29 +02001/*
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 Helgason03e85d22019-04-25 08:57:41 +020013#import <objc/runtime.h>
14
Anders Carlsson7bca8ca2018-08-30 09:30:29 +020015#include "rtc_base/numerics/safe_conversions.h"
Kári Tristan Helgasonecbdbf62020-02-20 07:34:45 -080016#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}
Anders Carlsson7bca8ca2018-08-30 09:30:29 +020039
Niels Möller4d504c72019-06-18 15:56:56 +020040// 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;
Kári Tristan Helgason03e85d22019-04-25 08:57:41 +020046@end
Niels Möller4d504c72019-06-18 15:56:56 +020047@implementation RTCWrappedEncodedImageBuffer
Kári Tristan Helgason03e85d22019-04-25 08:57:41 +020048@synthesize buffer = _buffer;
Niels Möller4d504c72019-06-18 15:56:56 +020049- (instancetype)initWithEncodedImageBuffer:
50 (rtc::scoped_refptr<webrtc::EncodedImageBufferInterface>)buffer {
Kári Tristan Helgason03e85d22019-04-25 08:57:41 +020051 self = [super init];
52 if (self) {
53 _buffer = buffer;
54 }
55 return self;
56}
57@end
58
Mirko Bonadeia81e9c82020-05-04 16:14:32 +020059@implementation RTC_OBJC_TYPE (RTCEncodedImage)
60(Private)
Anders Carlsson7bca8ca2018-08-30 09:30:29 +020061
Mirko Bonadeia81e9c82020-05-04 16:14:32 +020062 - (rtc::scoped_refptr<webrtc::EncodedImageBufferInterface>)encodedData {
Niels Möller4d504c72019-06-18 15:56:56 +020063 RTCWrappedEncodedImageBuffer *wrappedBuffer =
64 objc_getAssociatedObject(self, @selector(encodedData));
Kári Tristan Helgason03e85d22019-04-25 08:57:41 +020065 return wrappedBuffer.buffer;
66}
67
Niels Möller4d504c72019-06-18 15:56:56 +020068- (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);
Kári Tristan Helgason03e85d22019-04-25 08:57:41 +020074}
75
Dillon Cower5963fdd2019-02-07 16:17:43 -080076- (instancetype)initWithNativeEncodedImage:(const webrtc::EncodedImage &)encodedImage {
Anders Carlsson7bca8ca2018-08-30 09:30:29 +020077 if (self = [super init]) {
Kári Tristan Helgasonecbdbf62020-02-20 07:34:45 -080078 // 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();
Anders Carlsson7bca8ca2018-08-30 09:30:29 +020081 // Wrap the buffer in NSData without copying, do not take ownership.
Kári Tristan Helgasonecbdbf62020-02-20 07:34:45 -080082 self.buffer = [NSData dataWithBytesNoCopy:self.encodedData->data()
Kári Tristan Helgasonba9e1b82020-03-16 16:49:11 +010083 length:encodedImage.size()
Niels Möller77536a22019-01-15 08:50:01 +010084 freeWhenDone:NO];
Anders Carlsson7bca8ca2018-08-30 09:30:29 +020085 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_);
Anders Carlsson7bca8ca2018-08-30 09:30:29 +020095 self.qp = @(encodedImage.qp_);
96 self.contentType = (encodedImage.content_type_ == webrtc::VideoContentType::SCREENSHARE) ?
97 RTCVideoContentTypeScreenshare :
98 RTCVideoContentTypeUnspecified;
99 }
100
101 return self;
102}
103
104- (webrtc::EncodedImage)nativeEncodedImage {
105 // Return the pointer without copying.
Kári Tristan Helgasonecbdbf62020-02-20 07:34:45 -0800106 webrtc::EncodedImage encodedImage;
107 if (self.encodedData) {
108 encodedImage.SetEncodedData(self.encodedData);
109 } else if (self.buffer) {
110 encodedImage.SetEncodedData(ObjCEncodedImageBuffer::Create(self.buffer));
111 }
112 encodedImage.set_size(self.buffer.length);
Anders Carlsson7bca8ca2018-08-30 09:30:29 +0200113 encodedImage._encodedWidth = rtc::dchecked_cast<uint32_t>(self.encodedWidth);
114 encodedImage._encodedHeight = rtc::dchecked_cast<uint32_t>(self.encodedHeight);
115 encodedImage.SetTimestamp(self.timeStamp);
116 encodedImage.capture_time_ms_ = self.captureTimeMs;
117 encodedImage.ntp_time_ms_ = self.ntpTimeMs;
118 encodedImage.timing_.flags = self.flags;
119 encodedImage.timing_.encode_start_ms = self.encodeStartMs;
120 encodedImage.timing_.encode_finish_ms = self.encodeFinishMs;
Niels Möller87e2d782019-03-07 10:18:23 +0100121 encodedImage._frameType = webrtc::VideoFrameType(self.frameType);
Anders Carlsson7bca8ca2018-08-30 09:30:29 +0200122 encodedImage.rotation_ = webrtc::VideoRotation(self.rotation);
Anders Carlsson7bca8ca2018-08-30 09:30:29 +0200123 encodedImage.qp_ = self.qp ? self.qp.intValue : -1;
124 encodedImage.content_type_ = (self.contentType == RTCVideoContentTypeScreenshare) ?
125 webrtc::VideoContentType::SCREENSHARE :
126 webrtc::VideoContentType::UNSPECIFIED;
127
128 return encodedImage;
129}
130
131@end