ObjC: Support non-native frames in encoder

Frames might be non-native, i.e. normal I420 frames, and we should
handle that in the encoder.

BUG=webrtc:7785,webrtc:7924

Review-Url: https://codereview.webrtc.org/2992943002
Cr-Commit-Position: refs/heads/master@{#19245}
This commit is contained in:
magjed
2017-08-04 02:05:32 -07:00
committed by Commit Bot
parent 3e8016e1d5
commit 512bee3dee

View File

@ -13,6 +13,7 @@
#include <string> #include <string>
#import "NSString+StdString.h" #import "NSString+StdString.h"
#import "RTCI420Buffer+Private.h"
#import "RTCVideoCodec+Private.h" #import "RTCVideoCodec+Private.h"
#import "WebRTC/RTCVideoCodec.h" #import "WebRTC/RTCVideoCodec.h"
#import "WebRTC/RTCVideoCodecFactory.h" #import "WebRTC/RTCVideoCodecFactory.h"
@ -33,6 +34,22 @@
namespace webrtc { namespace webrtc {
namespace { namespace {
id<RTCVideoFrameBuffer> nativeToRtcFrameBuffer(const rtc::scoped_refptr<VideoFrameBuffer> &buffer) {
return buffer->type() == VideoFrameBuffer::Type::kNative ?
static_cast<ObjCFrameBuffer *>(buffer.get())->wrapped_frame_buffer() :
[[RTCI420Buffer alloc] initWithFrameBuffer:buffer->ToI420()];
}
RTCVideoFrame *nativeToRtcFrame(const VideoFrame &frame) {
RTCVideoFrame *rtcFrame =
[[RTCVideoFrame alloc] initWithBuffer:nativeToRtcFrameBuffer(frame.video_frame_buffer())
rotation:RTCVideoRotation(frame.rotation())
timeStampNs:frame.timestamp_us() * rtc::kNumNanosecsPerMicrosec];
rtcFrame.timeStamp = frame.timestamp();
return rtcFrame;
}
class ObjCVideoEncoder : public VideoEncoder { class ObjCVideoEncoder : public VideoEncoder {
public: public:
ObjCVideoEncoder(id<RTCVideoEncoder> encoder) ObjCVideoEncoder(id<RTCVideoEncoder> encoder)
@ -53,14 +70,13 @@ class ObjCVideoEncoder : public VideoEncoder {
RTCRtpFragmentationHeader *header) { RTCRtpFragmentationHeader *header) {
EncodedImage encodedImage = [frame nativeEncodedImage]; EncodedImage encodedImage = [frame nativeEncodedImage];
// Handle types than can be converted into one of webrtc::CodecSpecificInfo's hard coded // Handle types than can be converted into one of CodecSpecificInfo's hard coded cases.
// cases.
CodecSpecificInfo codecSpecificInfo; CodecSpecificInfo codecSpecificInfo;
if ([info isKindOfClass:[RTCCodecSpecificInfoH264 class]]) { if ([info isKindOfClass:[RTCCodecSpecificInfoH264 class]]) {
codecSpecificInfo = [(RTCCodecSpecificInfoH264 *)info nativeCodecSpecificInfo]; codecSpecificInfo = [(RTCCodecSpecificInfoH264 *)info nativeCodecSpecificInfo];
} }
std::unique_ptr<webrtc::RTPFragmentationHeader> fragmentationHeader = std::unique_ptr<RTPFragmentationHeader> fragmentationHeader =
[header createNativeFragmentationHeader]; [header createNativeFragmentationHeader];
callback->OnEncodedImage(encodedImage, &codecSpecificInfo, fragmentationHeader.release()); callback->OnEncodedImage(encodedImage, &codecSpecificInfo, fragmentationHeader.release());
}]; }];
@ -73,17 +89,7 @@ class ObjCVideoEncoder : public VideoEncoder {
int32_t Encode(const VideoFrame &frame, int32_t Encode(const VideoFrame &frame,
const CodecSpecificInfo *codec_specific_info, const CodecSpecificInfo *codec_specific_info,
const std::vector<FrameType> *frame_types) { const std::vector<FrameType> *frame_types) {
RTC_CHECK(frame.video_frame_buffer()->type() == VideoFrameBuffer::Type::kNative); // CodecSpecificInfo only handles a hard coded list of codecs
id<RTCVideoFrameBuffer> frame_buffer =
static_cast<ObjCFrameBuffer *>(frame.video_frame_buffer().get())->wrapped_frame_buffer();
RTCVideoFrame *rtcFrame =
[[RTCVideoFrame alloc] initWithBuffer:frame_buffer
rotation:RTCVideoRotation(frame.rotation())
timeStampNs:frame.timestamp_us() * rtc::kNumNanosecsPerMicrosec];
rtcFrame.timeStamp = frame.timestamp();
// webrtc::CodecSpecificInfo only handles a hard coded list of codecs
id<RTCCodecSpecificInfo> rtcCodecSpecificInfo = nil; id<RTCCodecSpecificInfo> rtcCodecSpecificInfo = nil;
if (codec_specific_info) { if (codec_specific_info) {
if (strcmp(codec_specific_info->codec_name, "H264") == 0) { if (strcmp(codec_specific_info->codec_name, "H264") == 0) {
@ -99,8 +105,9 @@ class ObjCVideoEncoder : public VideoEncoder {
[rtcFrameTypes addObject:@(RTCFrameType(frame_types->at(i)))]; [rtcFrameTypes addObject:@(RTCFrameType(frame_types->at(i)))];
} }
return return [encoder_ encode:nativeToRtcFrame(frame)
[encoder_ encode:rtcFrame codecSpecificInfo:rtcCodecSpecificInfo frameTypes:rtcFrameTypes]; codecSpecificInfo:rtcCodecSpecificInfo
frameTypes:rtcFrameTypes];
} }
int32_t SetChannelParameters(uint32_t packet_loss, int64_t rtt) { return WEBRTC_VIDEO_CODEC_OK; } int32_t SetChannelParameters(uint32_t packet_loss, int64_t rtt) { return WEBRTC_VIDEO_CODEC_OK; }
@ -139,8 +146,7 @@ id<RTCVideoEncoderFactory> ObjCVideoEncoderFactory::wrapped_encoder_factory() co
return encoder_factory_; return encoder_factory_;
} }
webrtc::VideoEncoder *ObjCVideoEncoderFactory::CreateVideoEncoder( VideoEncoder *ObjCVideoEncoderFactory::CreateVideoEncoder(const cricket::VideoCodec &codec) {
const cricket::VideoCodec &codec) {
RTCVideoCodecInfo *info = [[RTCVideoCodecInfo alloc] initWithNativeVideoCodec:codec]; RTCVideoCodecInfo *info = [[RTCVideoCodecInfo alloc] initWithNativeVideoCodec:codec];
id<RTCVideoEncoder> encoder = [encoder_factory_ createEncoder:info]; id<RTCVideoEncoder> encoder = [encoder_factory_ createEncoder:info];
return new ObjCVideoEncoder(encoder); return new ObjCVideoEncoder(encoder);
@ -156,7 +162,7 @@ const std::vector<cricket::VideoCodec> &ObjCVideoEncoderFactory::supported_codec
return supported_codecs_; return supported_codecs_;
} }
void ObjCVideoEncoderFactory::DestroyVideoEncoder(webrtc::VideoEncoder *encoder) { void ObjCVideoEncoderFactory::DestroyVideoEncoder(VideoEncoder *encoder) {
delete encoder; delete encoder;
encoder = nullptr; encoder = nullptr;
} }