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;
}
}