Skip to content

Commit

Permalink
SGPlayer: Decoders.
Browse files Browse the repository at this point in the history
  • Loading branch information
libobjc committed Nov 25, 2019
1 parent ca4fe2a commit 32beda4
Show file tree
Hide file tree
Showing 12 changed files with 587 additions and 277 deletions.
20 changes: 18 additions & 2 deletions SGPlayer.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,12 @@
9C6F902C219BE154001051CE /* SGMutableAsset.m in Sources */ = {isa = PBXBuildFile; fileRef = 9C6F9028219BE154001051CE /* SGMutableAsset.m */; };
9C6F902D219BE154001051CE /* SGMutableAsset.m in Sources */ = {isa = PBXBuildFile; fileRef = 9C6F9028219BE154001051CE /* SGMutableAsset.m */; };
9C6F902E219BE154001051CE /* SGMutableAsset.m in Sources */ = {isa = PBXBuildFile; fileRef = 9C6F9028219BE154001051CE /* SGMutableAsset.m */; };
9C72614A238B7C0400403272 /* SGCodecContext.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C726148238B7C0300403272 /* SGCodecContext.h */; };
9C72614B238B7C0400403272 /* SGCodecContext.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C726148238B7C0300403272 /* SGCodecContext.h */; };
9C72614C238B7C0400403272 /* SGCodecContext.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C726148238B7C0300403272 /* SGCodecContext.h */; };
9C72614D238B7C0400403272 /* SGCodecContext.m in Sources */ = {isa = PBXBuildFile; fileRef = 9C726149238B7C0300403272 /* SGCodecContext.m */; };
9C72614E238B7C0400403272 /* SGCodecContext.m in Sources */ = {isa = PBXBuildFile; fileRef = 9C726149238B7C0300403272 /* SGCodecContext.m */; };
9C72614F238B7C0400403272 /* SGCodecContext.m in Sources */ = {isa = PBXBuildFile; fileRef = 9C726149238B7C0300403272 /* SGCodecContext.m */; };
9C82EEB121AE356D00E9D523 /* SGAudioProcessor.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C82EEAF21AE356D00E9D523 /* SGAudioProcessor.h */; settings = {ATTRIBUTES = (Public, ); }; };
9C82EEB221AE356D00E9D523 /* SGAudioProcessor.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C82EEAF21AE356D00E9D523 /* SGAudioProcessor.h */; settings = {ATTRIBUTES = (Public, ); }; };
9C82EEB321AE356D00E9D523 /* SGAudioProcessor.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C82EEAF21AE356D00E9D523 /* SGAudioProcessor.h */; settings = {ATTRIBUTES = (Public, ); }; };
Expand Down Expand Up @@ -703,6 +709,8 @@
9C66E1FD2188550D00B70DAA /* SGSWResample.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SGSWResample.m; sourceTree = "<group>"; };
9C6F9027219BE154001051CE /* SGMutableAsset.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SGMutableAsset.h; sourceTree = "<group>"; };
9C6F9028219BE154001051CE /* SGMutableAsset.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SGMutableAsset.m; sourceTree = "<group>"; };
9C726148238B7C0300403272 /* SGCodecContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SGCodecContext.h; sourceTree = "<group>"; };
9C726149238B7C0300403272 /* SGCodecContext.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SGCodecContext.m; sourceTree = "<group>"; };
9C82EEAF21AE356D00E9D523 /* SGAudioProcessor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SGAudioProcessor.h; sourceTree = "<group>"; };
9C82EEB021AE356D00E9D523 /* SGAudioProcessor.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SGAudioProcessor.m; sourceTree = "<group>"; };
9C853F1021BFD85D005552C6 /* SGVideoDescriptor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SGVideoDescriptor.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1228,12 +1236,14 @@
9C0B6CB5217DBA1800900F1E /* SGDecodable.h */,
9CF15DE320118E1100585326 /* SGDecodeLoop.h */,
9CF15DE420118E1100585326 /* SGDecodeLoop.m */,
9C3082C521251AC200B44298 /* SGDecodeContext.h */,
9C3082C621251AC200B44298 /* SGDecodeContext.m */,
9C3082CE212521AB00B44298 /* SGAudioDecoder.h */,
9C3082CF212521AB00B44298 /* SGAudioDecoder.m */,
9C3082C1212518EB00B44298 /* SGVideoDecoder.h */,
9C3082C2212518EC00B44298 /* SGVideoDecoder.m */,
9C3082C521251AC200B44298 /* SGDecodeContext.h */,
9C3082C621251AC200B44298 /* SGDecodeContext.m */,
9C726148238B7C0300403272 /* SGCodecContext.h */,
9C726149238B7C0300403272 /* SGCodecContext.m */,
);
path = SGDecoder;
sourceTree = "<group>";
Expand Down Expand Up @@ -1633,6 +1643,7 @@
9C86386821904A0900D730EC /* SGPLFTargets.h in Headers */,
9C86386921904A0900D730EC /* SGRenderer+Internal.h in Headers */,
9C17554A22C5B5B3003A93BC /* SGRenderTimer.h in Headers */,
9C72614B238B7C0400403272 /* SGCodecContext.h in Headers */,
9CA57933219DAA270061093B /* SGCodecDescriptor.h in Headers */,
9C86386B21904A0900D730EC /* SGPLFObject.h in Headers */,
9C8D6B8B22C4A19500985D55 /* SGMetalRenderPipeline.h in Headers */,
Expand Down Expand Up @@ -1742,6 +1753,7 @@
9CD79F132190068E00E39A7D /* SGMacro.h in Headers */,
9C8D6B8C22C4A19500985D55 /* SGMetalRenderPipeline.h in Headers */,
9CD79F1B2190068E00E39A7D /* SGFFmpeg.h in Headers */,
9C72614C238B7C0400403272 /* SGCodecContext.h in Headers */,
9C17554B22C5B5B3003A93BC /* SGRenderTimer.h in Headers */,
9CD79F232190068E00E39A7D /* SGPLFTargets.h in Headers */,
9CD79F242190068E00E39A7D /* SGRenderer+Internal.h in Headers */,
Expand Down Expand Up @@ -1827,6 +1839,7 @@
9C8D4E48200DFFC700ED8A58 /* SGPlayerItem.h in Headers */,
9C95D2C12152386C00079B38 /* SGURLAsset.h in Headers */,
9C2C559B2015B87400131E15 /* SGVideoFrame.h in Headers */,
9C72614A238B7C0400403272 /* SGCodecContext.h in Headers */,
9C389ACC20108C2E003259FF /* SGFrame.h in Headers */,
9CF15E1F2011BC5400585326 /* SGAudioFrame.h in Headers */,
9C935B9C21CCCA58007813F4 /* SGDescriptor+Internal.h in Headers */,
Expand Down Expand Up @@ -2041,6 +2054,7 @@
9CB01C97219E863D00B36CFA /* SGMutilDemuxer.m in Sources */,
9C86380E21904A0900D730EC /* SGMapping.m in Sources */,
9C22AE6C237AC19E004D33DE /* SGFrameReader.m in Sources */,
9C72614E238B7C0400403272 /* SGCodecContext.m in Sources */,
9CC2AD7A22A65C7B0095A081 /* SGPaddingDemuxer.m in Sources */,
9C6F902D219BE154001051CE /* SGMutableAsset.m in Sources */,
9C86381121904A0900D730EC /* SGFrameOutput.m in Sources */,
Expand Down Expand Up @@ -2125,6 +2139,7 @@
9CB01C98219E863D00B36CFA /* SGMutilDemuxer.m in Sources */,
9CD79EB52190068E00E39A7D /* SGMapping.m in Sources */,
9C22AE6D237AC19E004D33DE /* SGFrameReader.m in Sources */,
9C72614F238B7C0400403272 /* SGCodecContext.m in Sources */,
9CC2AD7B22A65C7B0095A081 /* SGPaddingDemuxer.m in Sources */,
9C6F902E219BE154001051CE /* SGMutableAsset.m in Sources */,
9CD79EB82190068E00E39A7D /* SGFrameOutput.m in Sources */,
Expand Down Expand Up @@ -2200,6 +2215,7 @@
9C1378B323026B3A00FE0CFD /* SGTrackSelection.m in Sources */,
9C2C55B82015D92100131E15 /* SGObjectQueue.m in Sources */,
9CE71918219C3F7900256485 /* SGURLSegment.m in Sources */,
9C72614D238B7C0400403272 /* SGCodecContext.m in Sources */,
9C8D6B5422C4A19500985D55 /* SGMetalTextureLoader.m in Sources */,
9C03E5F1212E645B001F0E1B /* SGVRProjection.m in Sources */,
9C525D5421AEC421005C5708 /* SGAudioDescriptor.m in Sources */,
Expand Down
10 changes: 5 additions & 5 deletions SGPlayer/Classes/Core/SGDecoder/SGAudioDecoder.m
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#import "SGFrame+Internal.h"
#import "SGPacket+Internal.h"
#import "SGDescriptor+Internal.h"
#import "SGDecodeContext.h"
#import "SGCodecContext.h"
#import "SGAudioFrame.h"
#import "SGSonic.h"

Expand All @@ -26,7 +26,7 @@ @interface SGAudioDecoder ()
}

@property (nonatomic, strong, readonly) SGSonic *sonic;
@property (nonatomic, strong, readonly) SGDecodeContext *codecContext;
@property (nonatomic, strong, readonly) SGCodecContext *codecContext;
@property (nonatomic, strong, readonly) SGCodecDescriptor *codecDescriptor;
@property (nonatomic, strong, readonly) SGAudioDescriptor *audioDescriptor;

Expand All @@ -46,9 +46,9 @@ - (void)setup
self->_flags.nextTimeStamp = 0;
self->_flags.needsAlignment = YES;
self->_flags.needsResetSonic = YES;
self->_codecContext = [[SGDecodeContext alloc] initWithTimebase:self->_codecDescriptor.timebase
codecpar:self->_codecDescriptor.codecpar
frameGenerator:^__kindof SGFrame *{
self->_codecContext = [[SGCodecContext alloc] initWithTimebase:self->_codecDescriptor.timebase
codecpar:self->_codecDescriptor.codecpar
frameGenerator:^__kindof SGFrame *{
return [SGAudioFrame frame];
}];
self->_codecContext.options = self->_options;
Expand Down
52 changes: 52 additions & 0 deletions SGPlayer/Classes/Core/SGDecoder/SGCodecContext.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
//
// SGCodecContext.h
// SGPlayer iOS
//
// Created by Single on 2018/8/16.
// Copyright © 2018 single. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "SGCodecDescriptor.h"
#import "SGDecoderOptions.h"
#import "SGPacket.h"
#import "SGFrame.h"

@interface SGCodecContext : NSObject

+ (instancetype)new NS_UNAVAILABLE;
- (instancetype)init NS_UNAVAILABLE;

/**
*
*/
- (instancetype)initWithTimebase:(AVRational)timebase
codecpar:(AVCodecParameters *)codecpar
frameGenerator:(__kindof SGFrame *(^)(void))frameGenerator;

/**
*
*/
@property (nonatomic, strong) SGDecoderOptions *options;

/**
*
*/
- (BOOL)open;

/**
*
*/
- (void)close;

/**
*
*/
- (void)flush;

/**
*
*/
- (NSArray<__kindof SGFrame *> *)decode:(SGPacket *)packet;

@end
184 changes: 184 additions & 0 deletions SGPlayer/Classes/Core/SGDecoder/SGCodecContext.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
//
// SGCodecContext.m
// SGPlayer iOS
//
// Created by Single on 2018/8/16.
// Copyright © 2018 single. All rights reserved.
//

#import "SGCodecContext.h"
#import "SGPacket+Internal.h"
#import "SGFrame+Internal.h"
#import "SGMapping.h"
#import "SGOptions.h"
#import "SGError.h"
#import "SGMacro.h"

@interface SGCodecContext ()

@property (nonatomic, readonly) AVRational timebase;
@property (nonatomic, readonly) AVCodecParameters *codecpar;
@property (nonatomic, readonly) AVCodecContext *codecContext;
@property (nonatomic, copy, readonly) __kindof SGFrame *(^frameGenerator)(void);

@end

@implementation SGCodecContext

- (instancetype)initWithTimebase:(AVRational)timebase
codecpar:(AVCodecParameters *)codecpar
frameGenerator:(__kindof SGFrame *(^)(void))frameGenerator
{
if (self = [super init]) {
self->_timebase = timebase;
self->_codecpar = codecpar;
self->_frameGenerator = frameGenerator;
self->_options = [SGOptions sharedOptions].decoder.copy;
}
return self;
}

- (void)dealloc
{
[self close];
}

#pragma mark - Interface

- (BOOL)open
{
if (!self->_codecpar) {
return NO;
}
self->_codecContext = [self createCcodecContext];
if (!self->_codecContext) {
return NO;
}
return YES;
}

- (void)close
{
if (self->_codecContext) {
avcodec_free_context(&self->_codecContext);
self->_codecContext = nil;
}
}

- (void)flush
{
if (self->_codecContext) {
avcodec_flush_buffers(self->_codecContext);
}
}

- (NSArray<__kindof SGFrame *> *)decode:(SGPacket *)packet
{
if (!self->_codecContext) {
return nil;
}
int result = avcodec_send_packet(self->_codecContext, packet ? packet.core : NULL);
if (result < 0) {
return nil;
}
NSMutableArray *array = [NSMutableArray array];
while (result != AVERROR(EAGAIN)) {
__kindof SGFrame *frame = self->_frameGenerator();
result = avcodec_receive_frame(self->_codecContext, frame.core);
if (result < 0) {
[frame unlock];
break;
} else {
[array addObject:frame];
}
}
return array;
}

#pragma mark - AVCodecContext

- (AVCodecContext *)createCcodecContext
{
AVCodecContext *codecContext = avcodec_alloc_context3(NULL);
if (!codecContext) {
return nil;
}
codecContext->opaque = (__bridge void *)self;

int result = avcodec_parameters_to_context(codecContext, self->_codecpar);
NSError *error = SGGetFFError(result, SGActionCodeCodecSetParametersToContext);
if (error) {
avcodec_free_context(&codecContext);
return nil;
}
codecContext->pkt_timebase = self->_timebase;
if ((self->_options.hardwareDecodeH264 && self->_codecpar->codec_id == AV_CODEC_ID_H264) ||
(self->_options.hardwareDecodeH265 && self->_codecpar->codec_id == AV_CODEC_ID_H265)) {
codecContext->get_format = SGCodecContextGetFormat;
}

AVCodec *codec = avcodec_find_decoder(codecContext->codec_id);
if (!codec) {
avcodec_free_context(&codecContext);
return nil;
}
codecContext->codec_id = codec->id;

AVDictionary *opts = SGDictionaryNS2FF(self->_options.options);
if (self->_options.threadsAuto &&
!av_dict_get(opts, "threads", NULL, 0)) {
av_dict_set(&opts, "threads", "auto", 0);
}
if (self->_options.refcountedFrames &&
!av_dict_get(opts, "refcounted_frames", NULL, 0) &&
(codecContext->codec_type == AVMEDIA_TYPE_VIDEO || codecContext->codec_type == AVMEDIA_TYPE_AUDIO)) {
av_dict_set(&opts, "refcounted_frames", "1", 0);
}

result = avcodec_open2(codecContext, codec, &opts);

if (opts) {
av_dict_free(&opts);
}

error = SGGetFFError(result, SGActionCodeCodecOpen2);
if (error) {
avcodec_free_context(&codecContext);
return nil;
}

return codecContext;
}

static enum AVPixelFormat SGCodecContextGetFormat(struct AVCodecContext *s, const enum AVPixelFormat *fmt)
{
SGCodecContext *self = (__bridge SGCodecContext *)s->opaque;
for (int i = 0; fmt[i] != AV_PIX_FMT_NONE; i++) {
if (fmt[i] == AV_PIX_FMT_VIDEOTOOLBOX) {
AVBufferRef *device_ctx = av_hwdevice_ctx_alloc(AV_HWDEVICE_TYPE_VIDEOTOOLBOX);
if (!device_ctx) {
break;
}
AVBufferRef *frames_ctx = av_hwframe_ctx_alloc(device_ctx);
av_buffer_unref(&device_ctx);
if (!frames_ctx) {
break;
}
AVHWFramesContext *frames_ctx_data = (AVHWFramesContext *)frames_ctx->data;
frames_ctx_data->format = AV_PIX_FMT_VIDEOTOOLBOX;
frames_ctx_data->sw_format = SGPixelFormatAV2FF(self->_options.preferredPixelFormat);
frames_ctx_data->width = s->width;
frames_ctx_data->height = s->height;
int err = av_hwframe_ctx_init(frames_ctx);
if (err < 0) {
av_buffer_unref(&frames_ctx);
break;
}
s->hw_frames_ctx = frames_ctx;
return fmt[i];
}
}
return fmt[0];
}

@end
Loading

0 comments on commit 32beda4

Please sign in to comment.