Project import generated by Copybara.

PiperOrigin-RevId: 264105834
This commit is contained in:
MediaPipe Team
2019-08-19 08:50:18 +00:00
committed by Camillo Lugaresi
parent 71a47bb18b
commit f5df228d9b
28 changed files with 276 additions and 257 deletions
+15 -15
View File
@@ -15,20 +15,20 @@
#import <Foundation/Foundation.h>
#import <GLKit/GLKit.h>
/// Modes of clockwise rotation for input frames.
typedef enum {
MediaPipeFrameRotationNone,
MediaPipeFrameRotation90,
MediaPipeFrameRotation180,
MediaPipeFrameRotation270
} MediaPipeFrameRotationMode;
/// Modes of rotation (clockwise) for input frames.
typedef NS_ENUM(int, MPPFrameRotation) {
MPPFrameRotationNone,
MPPFrameRotationCw90,
MPPFrameRotationCw180,
MPPFrameRotationCw270,
};
typedef enum {
typedef NS_ENUM(int, MPPFrameScaleMode) {
// Scale the frame up to fit the drawing area, preserving aspect ratio; may letterbox.
MediaPipeFrameScaleFit,
MPPFrameScaleModeFit,
// Scale the frame up to fill the drawing area, preserving aspect ratio; may crop.
MediaPipeFrameScaleFillAndCrop,
} MediaPipeFrameScaleMode;
MPPFrameScaleModeFillAndCrop,
};
/// Renders frames in a GLKView.
@interface MPPGLViewRenderer : NSObject <GLKViewDelegate>
@@ -47,15 +47,15 @@ typedef enum {
@property(nonatomic, assign) BOOL retainsLastPixelBuffer;
/// Sets which way to rotate input frames before rendering them.
/// Default value is MediaPipeFrameRotationNone.
/// Default value is MPPFrameRotationNone.
/// Note that changing the transform property of a GLKView once rendering has
/// started causes problems inside GLKView. Instead, we perform the rotation
/// in our rendering code.
@property(nonatomic) MediaPipeFrameRotationMode frameRotationMode;
@property(nonatomic) MPPFrameRotation frameRotationMode;
/// Sets how to scale the frame within the view.
/// Default value is MediaPipeFrameScaleScaleToFit.
@property(nonatomic) MediaPipeFrameScaleMode frameScaleMode;
/// Default value is MPPFrameScaleModeFit.
@property(nonatomic) MPPFrameScaleMode frameScaleMode;
/// If YES, swap left and right. Useful for the front camera.
@property(nonatomic) BOOL mirrored;
+10 -10
View File
@@ -46,8 +46,8 @@
if (self) {
_glContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
_bufferLock = OS_SPINLOCK_INIT;
_frameRotationMode = MediaPipeFrameRotationNone;
_frameScaleMode = MediaPipeFrameScaleFit;
_frameRotationMode = MPPFrameRotationNone;
_frameScaleMode = MPPFrameScaleModeFit;
}
return self;
}
@@ -90,24 +90,24 @@
@"renderer setup failed: %@", [NSError gus_errorWithStatus:status]);
}
mediapipe::FrameScaleMode InternalScaleMode(MediaPipeFrameScaleMode mode) {
mediapipe::FrameScaleMode InternalScaleMode(MPPFrameScaleMode mode) {
switch (mode) {
case MediaPipeFrameScaleFit:
case MPPFrameScaleModeFit:
return mediapipe::FrameScaleMode::kFit;
case MediaPipeFrameScaleFillAndCrop:
case MPPFrameScaleModeFillAndCrop:
return mediapipe::FrameScaleMode::kFillAndCrop;
}
}
mediapipe::FrameRotation InternalRotationMode(MediaPipeFrameRotationMode rot) {
mediapipe::FrameRotation InternalRotationMode(MPPFrameRotation rot) {
switch (rot) {
case MediaPipeFrameRotationNone:
case MPPFrameRotationNone:
return mediapipe::FrameRotation::kNone;
case MediaPipeFrameRotation90:
case MPPFrameRotationCw90:
return mediapipe::FrameRotation::k90;
case MediaPipeFrameRotation180:
case MPPFrameRotationCw180:
return mediapipe::FrameRotation::k180;
case MediaPipeFrameRotation270:
case MPPFrameRotationCw270:
return mediapipe::FrameRotation::k270;
}
}
+2 -2
View File
@@ -50,7 +50,7 @@
MPPGraph* mediapipeGraph = [[MPPGraph alloc] initWithGraphConfig:config];
// We receive output by setting ourselves as the delegate.
mediapipeGraph.delegate = self;
[mediapipeGraph addFrameOutputStream:"output_video" outputPacketType:MediaPipePacketPixelBuffer];
[mediapipeGraph addFrameOutputStream:"output_video" outputPacketType:MPPPacketTypePixelBuffer];
// Start running the graph.
NSError *error;
@@ -60,7 +60,7 @@
// Send a frame.
XCTAssertTrue([mediapipeGraph sendPixelBuffer:*_inputPixelBuffer
intoStream:"input_video"
packetType:MediaPipePacketPixelBuffer
packetType:MPPPacketTypePixelBuffer
timestamp:mediapipe::Timestamp(0)]);
// Shut down the graph.
+10 -10
View File
@@ -54,26 +54,26 @@ struct GpuSharedData;
/// Chooses the packet type used by MPPGraph to send and receive packets
/// from the graph.
typedef NS_ENUM(int, MediaPipePacketType) {
typedef NS_ENUM(int, MPPPacketType) {
/// Any packet type.
/// Calls mediapipeGraph:didOutputPacket:fromStream:
MediaPipePacketRaw,
MPPPacketTypeRaw,
/// CFHolder<CVPixelBufferRef>.
/// Calls mediapipeGraph:didOutputPixelBuffer:fromStream:
/// Use this packet type to pass GPU frames to calculators.
MediaPipePacketPixelBuffer,
MPPPacketTypePixelBuffer,
/// ImageFrame.
/// Calls mediapipeGraph:didOutputPixelBuffer:fromStream:
MediaPipePacketImageFrame,
MPPPacketTypeImageFrame,
/// RGBA ImageFrame, but do not swap the channels if the input pixel buffer
/// is BGRA. This is useful when the graph needs RGBA ImageFrames, but the
/// calculators do not care about the order of the channels, so BGRA data can
/// be used as-is.
/// Calls mediapipeGraph:didOutputPixelBuffer:fromStream:
MediaPipePacketImageFrameBGRANoSwap,
MPPPacketTypeImageFrameBGRANoSwap,
};
/// This class is an Objective-C wrapper around a MediaPipe graph object, and
@@ -129,7 +129,7 @@ typedef NS_ENUM(int, MediaPipePacketType) {
/// the delegate will receive frames.
/// @param packetType The type of packet provided by the output streams.
- (void)addFrameOutputStream:(const std::string&)outputStreamName
outputPacketType:(MediaPipePacketType)packetType;
outputPacketType:(MPPPacketType)packetType;
/// Starts running the graph.
/// @return YES if successful.
@@ -155,7 +155,7 @@ typedef NS_ENUM(int, MediaPipePacketType) {
/// Creates a MediaPipe packet wrapping the given pixelBuffer;
- (mediapipe::Packet)packetWithPixelBuffer:(CVPixelBufferRef)pixelBuffer
packetType:(MediaPipePacketType)packetType;
packetType:(MPPPacketType)packetType;
/// Sends a pixel buffer into a graph input stream, using the specified packet
/// type. The graph must have been started before calling this. Drops frames and
@@ -164,7 +164,7 @@ typedef NS_ENUM(int, MediaPipePacketType) {
/// possibly increased efficiency. Returns YES if the packet was successfully sent.
- (BOOL)sendPixelBuffer:(CVPixelBufferRef)imageBuffer
intoStream:(const std::string&)inputName
packetType:(MediaPipePacketType)packetType
packetType:(MPPPacketType)packetType
timestamp:(const mediapipe::Timestamp&)timestamp
allowOverwrite:(BOOL)allowOverwrite;
@@ -174,7 +174,7 @@ typedef NS_ENUM(int, MediaPipePacketType) {
/// successfully sent.
- (BOOL)sendPixelBuffer:(CVPixelBufferRef)pixelBuffer
intoStream:(const std::string&)inputName
packetType:(MediaPipePacketType)packetType
packetType:(MPPPacketType)packetType
timestamp:(const mediapipe::Timestamp&)timestamp;
/// Sends a pixel buffer into a graph input stream, using the specified packet
@@ -184,7 +184,7 @@ typedef NS_ENUM(int, MediaPipePacketType) {
/// packet was successfully sent.
- (BOOL)sendPixelBuffer:(CVPixelBufferRef)pixelBuffer
intoStream:(const std::string&)inputName
packetType:(MediaPipePacketType)packetType;
packetType:(MPPPacketType)packetType;
/// Cancels a graph run. You must still call waitUntilDoneWithError: after this.
- (void)cancel;
+12 -12
View File
@@ -77,7 +77,7 @@
}
- (void)addFrameOutputStream:(const std::string&)outputStreamName
outputPacketType:(MediaPipePacketType)packetType {
outputPacketType:(MPPPacketType)packetType {
std::string callbackInputName;
mediapipe::tool::AddCallbackCalculator(outputStreamName, &_config, &callbackInputName,
/*use_std_function=*/true);
@@ -99,14 +99,14 @@
/// This is the function that gets called by the CallbackCalculator that
/// receives the graph's output.
void CallFrameDelegate(void* wrapperVoid, const std::string& streamName,
MediaPipePacketType packetType, const mediapipe::Packet& packet) {
MPPPacketType packetType, const mediapipe::Packet& packet) {
MPPGraph* wrapper = (__bridge MPPGraph*)wrapperVoid;
@autoreleasepool {
if (packetType == MediaPipePacketRaw) {
if (packetType == MPPPacketTypeRaw) {
[wrapper.delegate mediapipeGraph:wrapper
didOutputPacket:packet
fromStream:streamName];
} else if (packetType == MediaPipePacketImageFrame) {
} else if (packetType == MPPPacketTypeImageFrame) {
const auto& frame = packet.Get<mediapipe::ImageFrame>();
mediapipe::ImageFormat::Format format = frame.Format();
@@ -162,7 +162,7 @@ void CallFrameDelegate(void* wrapperVoid, const std::string& streamName,
_GTMDevLog(@"unsupported ImageFormat: %d", format);
}
#if MEDIAPIPE_GPU_BUFFER_USE_CV_PIXEL_BUFFER
} else if (packetType == MediaPipePacketPixelBuffer) {
} else if (packetType == MPPPacketTypePixelBuffer) {
CVPixelBufferRef pixelBuffer = packet.Get<mediapipe::GpuBuffer>().GetCVPixelBufferRef();
if ([wrapper.delegate
respondsToSelector:@selector
@@ -283,15 +283,15 @@ void CallFrameDelegate(void* wrapperVoid, const std::string& streamName,
}
- (mediapipe::Packet)packetWithPixelBuffer:(CVPixelBufferRef)imageBuffer
packetType:(MediaPipePacketType)packetType {
packetType:(MPPPacketType)packetType {
mediapipe::Packet packet;
if (packetType == MediaPipePacketImageFrame || packetType == MediaPipePacketImageFrameBGRANoSwap) {
if (packetType == MPPPacketTypeImageFrame || packetType == MPPPacketTypeImageFrameBGRANoSwap) {
auto frame = CreateImageFrameForCVPixelBuffer(
imageBuffer, /* canOverwrite = */ false,
/* bgrAsRgb = */ packetType == MediaPipePacketImageFrameBGRANoSwap);
/* bgrAsRgb = */ packetType == MPPPacketTypeImageFrameBGRANoSwap);
packet = mediapipe::Adopt(frame.release());
#if MEDIAPIPE_GPU_BUFFER_USE_CV_PIXEL_BUFFER
} else if (packetType == MediaPipePacketPixelBuffer) {
} else if (packetType == MPPPacketTypePixelBuffer) {
packet = mediapipe::MakePacket<mediapipe::GpuBuffer>(imageBuffer);
#endif // MEDIAPIPE_GPU_BUFFER_USE_CV_PIXEL_BUFFER
} else {
@@ -302,7 +302,7 @@ void CallFrameDelegate(void* wrapperVoid, const std::string& streamName,
- (BOOL)sendPixelBuffer:(CVPixelBufferRef)imageBuffer
intoStream:(const std::string&)inputName
packetType:(MediaPipePacketType)packetType
packetType:(MPPPacketType)packetType
timestamp:(const mediapipe::Timestamp&)timestamp
allowOverwrite:(BOOL)allowOverwrite {
if (_maxFramesInFlight && _framesInFlight >= _maxFramesInFlight) return NO;
@@ -326,7 +326,7 @@ void CallFrameDelegate(void* wrapperVoid, const std::string& streamName,
- (BOOL)sendPixelBuffer:(CVPixelBufferRef)imageBuffer
intoStream:(const std::string&)inputName
packetType:(MediaPipePacketType)packetType
packetType:(MPPPacketType)packetType
timestamp:(const mediapipe::Timestamp&)timestamp {
return [self sendPixelBuffer:imageBuffer
intoStream:inputName
@@ -337,7 +337,7 @@ void CallFrameDelegate(void* wrapperVoid, const std::string& streamName,
- (BOOL)sendPixelBuffer:(CVPixelBufferRef)imageBuffer
intoStream:(const std::string&)inputName
packetType:(MediaPipePacketType)packetType {
packetType:(MPPPacketType)packetType {
_GTMDevAssert(_frameTimestamp < mediapipe::Timestamp::Done(),
@"Trying to send frame after stream is done.");
if (_frameTimestamp < mediapipe::Timestamp::Min()) {
+2 -2
View File
@@ -43,7 +43,7 @@
/// completes the run, and returns the output frame.
- (CVPixelBufferRef)runGraph:(MPPGraph*)graph
withPixelBuffer:(CVPixelBufferRef)inputBuffer
packetType:(MediaPipePacketType)inputPacketType;
packetType:(MPPPacketType)inputPacketType;
/// Runs a simple graph, providing a single frame to zero or more inputs. Input images are wrapped
/// in packets each with timestamp mediapipe::Timestamp(1). Those packets are added to the
@@ -53,7 +53,7 @@
withInputPixelBuffers:
(const std::unordered_map<std::string, CFHolder<CVPixelBufferRef>>&)inputBuffers
outputStream:(const std::string&)output
packetType:(MediaPipePacketType)inputPacketType;
packetType:(MPPPacketType)inputPacketType;
/// Loads a data file from the test bundle.
- (NSData*)testDataNamed:(NSString*)name extension:(NSString*)extension;
+6 -6
View File
@@ -81,7 +81,7 @@ static void EnsureOutputDirFor(NSString *outputFile) {
inputPackets:(const std::map<std::string, mediapipe::Packet>&)inputPackets
timestamp:(mediapipe::Timestamp)timestamp
outputStream:(const std::string&)outputStream
packetType:(MediaPipePacketType)inputPacketType {
packetType:(MPPPacketType)inputPacketType {
__block CVPixelBufferRef output;
graph.delegate = self;
@@ -143,7 +143,7 @@ static void EnsureOutputDirFor(NSString *outputFile) {
- (CVPixelBufferRef)runGraph:(MPPGraph*)graph
withPixelBuffer:(CVPixelBufferRef)inputBuffer
packetType:(MediaPipePacketType)inputPacketType {
packetType:(MPPPacketType)inputPacketType {
return [self runGraph:graph
withInputPixelBuffers:{{"input_frames", MakeCFHolder(inputBuffer)}}
inputPackets:{}
@@ -156,7 +156,7 @@ static void EnsureOutputDirFor(NSString *outputFile) {
withInputPixelBuffers:
(const std::unordered_map<std::string, CFHolder<CVPixelBufferRef>>&)inputBuffers
outputStream:(const std::string&)output
packetType:(MediaPipePacketType)inputPacketType {
packetType:(MPPPacketType)inputPacketType {
return [self runGraph:graph
withInputPixelBuffers:inputBuffers
inputPackets:{}
@@ -362,7 +362,7 @@ static void EnsureOutputDirFor(NSString *outputFile) {
{
CVPixelBufferRef outputBuffer = [self runGraph:graph
withPixelBuffer:inputBuffer
packetType:MediaPipePacketPixelBuffer];
packetType:MPPPacketTypePixelBuffer];
#if DEBUG
// Xcode can display UIImage objects right in the debugger. It is handy to
// have these variables defined if the test fails.
@@ -405,7 +405,7 @@ static void EnsureOutputDirFor(NSString *outputFile) {
MPPGraph* graph = [[MPPGraph alloc] initWithGraphConfig:config];
[graph addSidePackets:sidePackets];
[graph addFrameOutputStream:outputStream.UTF8String
outputPacketType:MediaPipePacketPixelBuffer];
outputPacketType:MPPPacketTypePixelBuffer];
std::unordered_map<std::string, CFHolder<CVPixelBufferRef>> inputBuffers;
for (NSString* inputStream in fileInputs) {
@@ -428,7 +428,7 @@ static void EnsureOutputDirFor(NSString *outputFile) {
inputPackets:packetInputs
timestamp:timestamp
outputStream:outputStream.UTF8String
packetType:MediaPipePacketPixelBuffer];
packetType:MPPPacketTypePixelBuffer];
UIImage* output = UIImageWithPixelBuffer(outputBuffer);
XCTAssertNotNil(output);
+13 -13
View File
@@ -125,13 +125,13 @@ REGISTER_CALCULATOR(ErrorCalculator);
node->add_output_stream("output_frames");
_graph = [[MPPGraph alloc] initWithGraphConfig:config];
[_graph addFrameOutputStream:"output_frames" outputPacketType:MediaPipePacketPixelBuffer];
[_graph addFrameOutputStream:"output_frames" outputPacketType:MPPPacketTypePixelBuffer];
CFHolder<CVPixelBufferRef> inputBuffer;
::mediapipe::Status status = CreateCVPixelBufferFromCGImage(_sourceImage.CGImage, &inputBuffer);
XCTAssert(status.ok());
CVPixelBufferRef outputBuffer = [self runGraph:_graph
withPixelBuffer:*inputBuffer
packetType:MediaPipePacketPixelBuffer];
packetType:MPPPacketTypePixelBuffer];
XCTAssert([self pixelBuffer:outputBuffer isEqualTo:*inputBuffer]);
}
@@ -162,8 +162,8 @@ REGISTER_CALCULATOR(ErrorCalculator);
grayNode->add_output_stream("gray_frames");
_graph = [[MPPGraph alloc] initWithGraphConfig:config];
[_graph addFrameOutputStream:"pass_frames" outputPacketType:MediaPipePacketImageFrame];
[_graph addFrameOutputStream:"gray_frames" outputPacketType:MediaPipePacketImageFrame];
[_graph addFrameOutputStream:"pass_frames" outputPacketType:MPPPacketTypeImageFrame];
[_graph addFrameOutputStream:"gray_frames" outputPacketType:MPPPacketTypeImageFrame];
CFHolder<CVPixelBufferRef> inputBuffer;
::mediapipe::Status status = CreateCVPixelBufferFromCGImage(_sourceImage.CGImage, &inputBuffer);
@@ -185,7 +185,7 @@ REGISTER_CALCULATOR(ErrorCalculator);
}
};
[self runGraph:_graph withPixelBuffer:*inputBuffer packetType:MediaPipePacketImageFrame];
[self runGraph:_graph withPixelBuffer:*inputBuffer packetType:MPPPacketTypeImageFrame];
}
- (void)testGrayscaleOutput {
@@ -202,13 +202,13 @@ REGISTER_CALCULATOR(ErrorCalculator);
node->add_output_stream("output_frames");
_graph = [[MPPGraph alloc] initWithGraphConfig:config];
[_graph addFrameOutputStream:"output_frames" outputPacketType:MediaPipePacketImageFrame];
[_graph addFrameOutputStream:"output_frames" outputPacketType:MPPPacketTypeImageFrame];
CFHolder<CVPixelBufferRef> inputBuffer;
::mediapipe::Status status = CreateCVPixelBufferFromCGImage(grayImage.CGImage, &inputBuffer);
XCTAssert(status.ok());
CVPixelBufferRef outputBuffer = [self runGraph:_graph
withPixelBuffer:*inputBuffer
packetType:MediaPipePacketImageFrame];
packetType:MPPPacketTypeImageFrame];
// We accept a small difference due to gamma correction and whatnot.
XCTAssert([self pixelBuffer:outputBuffer isCloseTo:*inputBuffer
maxLocalDifference:5 maxAverageDifference:FLT_MAX]);
@@ -226,13 +226,13 @@ REGISTER_CALCULATOR(ErrorCalculator);
CreateCVPixelBufferFromCGImage(_sourceImage.CGImage, &srcPixelBuffer);
XCTAssert(status.ok());
_graph = [[MPPGraph alloc] initWithGraphConfig:config];
[_graph addFrameOutputStream:"output_frames" outputPacketType:MediaPipePacketImageFrame];
[_graph addFrameOutputStream:"output_frames" outputPacketType:MPPPacketTypeImageFrame];
_graph.delegate = self;
XCTAssert([_graph startWithError:nil]);
[_graph sendPixelBuffer:*srcPixelBuffer
intoStream:"input_frames"
packetType:MediaPipePacketImageFrame];
packetType:MPPPacketTypeImageFrame];
XCTAssert([_graph closeInputStream:"input_frames" error:nil]);
__block NSError* error = nil;
@@ -259,7 +259,7 @@ REGISTER_CALCULATOR(ErrorCalculator);
node->add_output_stream("output_frames");
_graph = [[MPPGraph alloc] initWithGraphConfig:config];
[_graph addFrameOutputStream:"output_frames" outputPacketType:MediaPipePacketImageFrame];
[_graph addFrameOutputStream:"output_frames" outputPacketType:MPPPacketTypeImageFrame];
// We're no longer using video headers, let's just use an int as the header.
auto header_packet = mediapipe::MakePacket<int>(0xDEADBEEF);
@@ -288,13 +288,13 @@ REGISTER_CALCULATOR(ErrorCalculator);
node->add_output_stream("output_frames");
_graph = [[MPPGraph alloc] initWithGraphConfig:config];
[_graph addFrameOutputStream:"output_frames" outputPacketType:MediaPipePacketPixelBuffer];
[_graph addFrameOutputStream:"output_frames" outputPacketType:MPPPacketTypePixelBuffer];
CFHolder<CVPixelBufferRef> inputBuffer;
::mediapipe::Status status = CreateCVPixelBufferFromCGImage(_sourceImage.CGImage, &inputBuffer);
XCTAssert(status.ok());
CVPixelBufferRef outputBuffer = [self runGraph:_graph
withPixelBuffer:*inputBuffer
packetType:MediaPipePacketPixelBuffer];
packetType:MPPPacketTypePixelBuffer];
__weak MPPGraph* weakGraph = _graph;
_graph = nil;
XCTAssertNil(weakGraph);
@@ -311,7 +311,7 @@ REGISTER_CALCULATOR(ErrorCalculator);
const int kTestValue = 10;
_graph = [[MPPGraph alloc] initWithGraphConfig:config];
[_graph addFrameOutputStream:"output_ints" outputPacketType:MediaPipePacketRaw];
[_graph addFrameOutputStream:"output_ints" outputPacketType:MPPPacketTypeRaw];
_graph.delegate = self;
WEAKIFY(self);
+3 -3
View File
@@ -26,12 +26,12 @@
- (void)renderPixelBuffer:(CVPixelBufferRef)pixelBuffer;
/// Sets which way to rotate input frames before rendering them.
/// Default value is MediaPipeFrameRotationNone.
@property(nonatomic) MediaPipeFrameRotationMode frameRotationMode;
/// Default value is MPPFrameRotationNone.
@property(nonatomic) MPPFrameRotation frameRotationMode;
/// Sets how to scale the frame within the layer.
/// Default value is MediaPipeFrameScaleScaleToFit.
@property(nonatomic) MediaPipeFrameScaleMode frameScaleMode;
@property(nonatomic) MPPFrameScaleMode frameScaleMode;
/// If YES, swap left and right. Useful for the front camera.
@property(nonatomic) BOOL mirrored;
+4 -4
View File
@@ -73,19 +73,19 @@
if (!success) NSLog(@"presentRenderbuffer failed");
}
- (MediaPipeFrameRotationMode)frameRotationMode {
- (MPPFrameRotation)frameRotationMode {
return _glRenderer.frameRotationMode;
}
- (void)setFrameRotationMode:(MediaPipeFrameRotationMode)frameRotationMode {
- (void)setFrameRotationMode:(MPPFrameRotation)frameRotationMode {
_glRenderer.frameRotationMode = frameRotationMode;
}
- (MediaPipeFrameScaleMode)frameScaleMode {
- (MPPFrameScaleMode)frameScaleMode {
return _glRenderer.frameScaleMode;
}
- (void)setFrameScaleMode:(MediaPipeFrameScaleMode)frameScaleMode {
- (void)setFrameScaleMode:(MPPFrameScaleMode)frameScaleMode {
_glRenderer.frameScaleMode = frameScaleMode;
}