iOS 扩展Ijkplayer解码方式

Ijkplayer框架中,解码方式的选择只有 智能硬解(硬解失败,自动转软解)、软解 两种,功能上讲,两种方式已够用,但偶尔也有需求让扩展成用户自选的三种解码方式:智能、硬解、软解。

下文讲的就是如何在原框架中,扩展出 硬解 的选项,及其失败后对应的消息处理:
1.在 ff_ffplay_options.h 文件下修改“videotoolbox”的最大值,范围由0 ~ 1,扩展到0 ~ 2:
0:软解
1:智能硬解
2:硬解
 { "videotoolbox",                       "VideoToolbox: enable",
        OPTION_OFFSET(videotoolbox),        OPTION_INT(0, 0, 2) },
在工程中创建播放器时,设置options选项,来选择视频的解码方式(默认是软解):
 [options setOptionIntValue:1 forKey:@"videotoolbox" ofCategory:kIJKFFOptionCategoryPlayer];
2.在实现选择解码方式的方法之前,需要先创建一个硬解失败的标志位,通过判断它来决定是否需要发送硬解失败的错误提示:

ff_ffpipeline.h 中,修改结构体:IJKFF_Pipeline * 添加布尔值 * bool video_decoder_from_ios_videotoolbox_failed;

3.修改 ffpipeline_ios.c 中 函数*func_open_video_decoder *的解码选择逻辑:
static IJKFF_Pipenode *func_open_video_decoder(IJKFF_Pipeline *pipeline, FFPlayer *ffp) {
   
    IJKFF_Pipenode* node = NULL;
    IJKFF_Pipeline_Opaque *opaque = pipeline->opaque;
    pipeline->video_decoder_from_ios_videotoolbox_failed = false;
    if (ffp->videotoolbox != 0) {
        node = ffpipenode_create_video_decoder_from_ios_videotoolbox(ffp);
        if (node) {
            ffp->stat.vdec_type = FFP_PROPV_DECODER_VIDEOTOOLBOX;
            opaque->is_videotoolbox_open = true;
        } else if (!node && ffp->videotoolbox == 1){
            node = ffpipenode_create_video_decoder_from_ffplay(ffp);
            ffp->stat.vdec_type = FFP_PROPV_DECODER_AVCODEC;
            opaque->is_videotoolbox_open = false;
        }
    } else {
        node = ffpipenode_create_video_decoder_from_ffplay(ffp);
        ffp->stat.vdec_type = FFP_PROPV_DECODER_AVCODEC;
        opaque->is_videotoolbox_open = false;
    }
    if(!node) {
        ffp->stat.vdec_type = FFP_PROPV_DECODER_UNKNOWN;
        pipeline->video_decoder_from_ios_videotoolbox_failed = true;
    }
    ffp_notify_msg2(ffp, FFP_MSG_VIDEO_DECODER_OPEN, opaque->is_videotoolbox_open);
    return node;
}

4.在 ff_ffplay.c 添加硬解失败消息处理,并阻止后续进程的继续操作:
 if(ffp->pipeline->video_decoder_from_ios_videotoolbox_failed){
        last_error = 19;//这个errorCode自己定义,建议稍大一点,不会和框架的重复
        goto fail;
    }

上段代码建议添加在下面代码的后面:

if (is->video_stream < 0 && is->audio_stream < 0) {
        av_log(NULL, AV_LOG_FATAL, "Failed to open file '%s' or configure filtergraph\n",
               is->filename);
        ret = -1;
        goto fail;
    }

5. * goto fail*之后,它会通过 *ffp_notify_msg2(ffp, FFP_MSG_ERROR, last_error); * 将错误消息发送出去,在 *IJKFFMoviePlayerController.m *中的 *- (void)postEvent: (IJKFFMoviePlayerMessage )msg 方法中将其转化成通知
  [[NSNotificationCenter defaultCenter] postNotificationName:IJKMPMoviePlayerPlaybackDidFinishNotification
                object:self
                userInfo:@{
                    IJKMPMoviePlayerPlaybackDidFinishReasonUserInfoKey: @(IJKMPMovieFinishReasonPlaybackError),
                    @"error": @(avmsg->arg1)}];

6.在工程中接收通知:
-(void)installMovieNotificationObservers {

[[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(moviePlayBackDidFinish:)
                                                 name:IJKMPMoviePlayerPlaybackDidFinishNotification
                                               object:_player]; 
}

- (void)moviePlayBackDidFinish:(NSNotification*)notification {

    int reason = [[[notification userInfo] valueForKey:IJKMPMoviePlayerPlaybackDidFinishReasonUserInfoKey] intValue];
    int errorCode = [[[notification userInfo] valueForKey:@"error"] intValue];
    switch (reason)   {
        case IJKMPMovieFinishReasonPlaybackError:
            if (errorCode == 19) {
                NSLog(@"硬解失败");
            }
            break;
        default:
            break;
    }
}

你可能感兴趣的:(iOS 扩展Ijkplayer解码方式)