diff --git a/ijkmedia/ijkplayer/android/pipeline/ffpipenode_android_mediacodec_vdec.c b/ijkmedia/ijkplayer/android/pipeline/ffpipenode_android_mediacodec_vdec.c index d4d2238546a3eaba0d39602f7b39d18d118869d0..edbdee51b2c71e48a005e9e3233e20cae36f38c0 100644 --- a/ijkmedia/ijkplayer/android/pipeline/ffpipenode_android_mediacodec_vdec.c +++ b/ijkmedia/ijkplayer/android/pipeline/ffpipenode_android_mediacodec_vdec.c @@ -719,7 +719,7 @@ static int drain_output_buffer_l(JNIEnv *env, IJKFF_Pipenode *node, int64_t time } } } else if (output_buffer_index >= 0) { - ffp->vdps = SDL_SpeedSamplerAdd(&opaque->sampler, FFP_SHOW_VDPS_MEDIACODEC, "vdps[MediaCodec]"); + ffp->stat.vdps = SDL_SpeedSamplerAdd(&opaque->sampler, FFP_SHOW_VDPS_MEDIACODEC, "vdps[MediaCodec]"); if (dequeue_count) ++*dequeue_count; diff --git a/ijkmedia/ijkplayer/ff_ffmsg.h b/ijkmedia/ijkplayer/ff_ffmsg.h index 82043b64d29b017b257aca6ee79334421ce20c73..a240a06e7f367c5ba3caf9b44909c7d6c0fea66a 100644 --- a/ijkmedia/ijkplayer/ff_ffmsg.h +++ b/ijkmedia/ijkplayer/ff_ffmsg.h @@ -50,8 +50,22 @@ #define FFP_PROP_FLOAT_VIDEO_DECODE_FRAMES_PER_SECOND 10001 #define FFP_PROP_FLOAT_VIDEO_OUTPUT_FRAMES_PER_SECOND 10002 #define FFP_PROP_FLOAT_PLAYBACK_RATE 10003 +#define FFP_PROP_FLOAT_AVDELAY 10004 +#define FFP_PROP_FLOAT_AVDIFF 10005 -#define FFP_PROP_INT64_SELECTED_VIDEO_STREAM 20001 -#define FFP_PROP_INT64_SELECTED_AUDIO_STREAM 20002 +#define FFP_PROP_INT64_SELECTED_VIDEO_STREAM 20001 +#define FFP_PROP_INT64_SELECTED_AUDIO_STREAM 20002 +#define FFP_PROP_INT64_VIDEO_DECODER 20003 +#define FFP_PROP_INT64_AUDIO_DECODER 20004 +#define FFP_PROPV_DECODER_UNKNOWN 0 +#define FFP_PROPV_DECODER_AVCODEC 1 +#define FFP_PROPV_DECODER_MEDIACODEC 2 +#define FFP_PROPV_DECODER_VIDEOTOOLBOX 3 +#define FFP_PROP_INT64_VIDEO_CACHED_DURATION 20005 +#define FFP_PROP_INT64_AUDIO_CACHED_DURATION 20006 +#define FFP_PROP_INT64_VIDEO_CACHED_BYTES 20007 +#define FFP_PROP_INT64_AUDIO_CACHED_BYTES 20008 +#define FFP_PROP_INT64_VIDEO_CACHED_PACKETS 20009 +#define FFP_PROP_INT64_AUDIO_CACHED_PACKETS 20010 #endif diff --git a/ijkmedia/ijkplayer/ff_ffplay.c b/ijkmedia/ijkplayer/ff_ffplay.c index 17ee00dc8dcafcb3957434fe517c2fc950d140ed..af6858d14fa7dd022f2139d200b40da165d5328b 100644 --- a/ijkmedia/ijkplayer/ff_ffplay.c +++ b/ijkmedia/ijkplayer/ff_ffplay.c @@ -398,7 +398,7 @@ static int decoder_decode_frame(FFPlayer *ffp, Decoder *d, AVFrame *frame, AVSub case AVMEDIA_TYPE_VIDEO: { ret = avcodec_decode_video2(d->avctx, frame, &got_frame, &d->pkt_temp); if (got_frame) { - ffp->vdps = SDL_SpeedSamplerAdd(&ffp->vdps_sampler, FFP_SHOW_VDPS_AVCODEC, "vdps[avcodec]"); + ffp->stat.vdps = SDL_SpeedSamplerAdd(&ffp->vdps_sampler, FFP_SHOW_VDPS_AVCODEC, "vdps[avcodec]"); if (ffp->decoder_reorder_pts == -1) { frame->pts = av_frame_get_best_effort_timestamp(frame); } else if (ffp->decoder_reorder_pts) { @@ -651,7 +651,7 @@ static void video_image_display2(FFPlayer *ffp) vp = frame_queue_peek(&is->pictq); if (vp->bmp) { SDL_VoutDisplayYUVOverlay(ffp->vout, vp->bmp); - ffp->vfps = SDL_SpeedSamplerAdd(&ffp->vfps_sampler, FFP_SHOW_VFPS_FFPLAY, "vfps[ffplay]"); + ffp->stat.vfps = SDL_SpeedSamplerAdd(&ffp->vfps_sampler, FFP_SHOW_VFPS_FFPLAY, "vfps[ffplay]"); if (!ffp->first_video_frame_rendered) { ffp->first_video_frame_rendered = 1; ffp_notify_msg1(ffp, FFP_MSG_VIDEO_RENDERING_START); @@ -950,7 +950,7 @@ static void step_to_next_frame_l(FFPlayer *ffp) is->step = 1; } -static double compute_target_delay(double delay, VideoState *is) +static double compute_target_delay(FFPlayer *ffp, double delay, VideoState *is) { double sync_threshold, diff = 0; @@ -974,6 +974,10 @@ static double compute_target_delay(double delay, VideoState *is) } } + if (ffp) { + ffp->stat.avdelay = delay; + ffp->stat.avdiff = diff; + } #ifdef FFP_SHOW_AUDIO_DELAY av_log(NULL, AV_LOG_TRACE, "video: delay=%0.3f A-V=%f\n", delay, -diff); @@ -1055,7 +1059,7 @@ retry: if (redisplay) delay = 0.0; else - delay = compute_target_delay(last_duration, is); + delay = compute_target_delay(ffp, last_duration, is); time= av_gettime_relative()/1000000.0; if (isnan(is->frame_timer) || time < is->frame_timer) @@ -3691,6 +3695,11 @@ void ffp_check_buffering_l(FFPlayer *ffp) int64_t audio_cached_duration = -1; int64_t video_cached_duration = -1; + ffp->stat.video_cached_bytes = is->videoq.size; + ffp->stat.audio_cached_bytes = is->audioq.size; + ffp->stat.video_cached_packets = is->videoq.nb_packets; + ffp->stat.audio_cached_packets = is->audioq.nb_packets; + if (is->audio_st && audio_time_base_valid) { audio_cached_duration = is->audioq.duration * av_q2d(is->audio_st->time_base) * 1000; #ifdef FFP_SHOW_DEMUX_CACHE @@ -3715,6 +3724,8 @@ void ffp_check_buffering_l(FFPlayer *ffp) is->audioq_duration = audio_cached_duration; is->videoq_duration = video_cached_duration; + ffp->stat.audio_cached_duration = audio_cached_duration; + ffp->stat.video_cached_duration = video_cached_duration; if (video_cached_duration > 0 && audio_cached_duration > 0) { cached_duration_in_ms = (int)IJKMIN(video_cached_duration, audio_cached_duration); @@ -3905,11 +3916,15 @@ float ffp_get_property_float(FFPlayer *ffp, int id, float default_value) { switch (id) { case FFP_PROP_FLOAT_VIDEO_DECODE_FRAMES_PER_SECOND: - return ffp ? ffp->vdps : default_value; + return ffp ? ffp->stat.vdps : default_value; case FFP_PROP_FLOAT_VIDEO_OUTPUT_FRAMES_PER_SECOND: - return ffp ? ffp->vfps : default_value; + return ffp ? ffp->stat.vfps : default_value; case FFP_PROP_FLOAT_PLAYBACK_RATE: return ffp ? ffp->pf_playback_rate : default_value; + case FFP_PROP_FLOAT_AVDELAY: + return ffp ? ffp->stat.avdelay : default_value; + case FFP_PROP_FLOAT_AVDIFF: + return ffp ? ffp->stat.avdiff : default_value; default: return default_value; } @@ -3936,6 +3951,37 @@ int64_t ffp_get_property_int64(FFPlayer *ffp, int id, int64_t default_value) if (!ffp || !ffp->is) return default_value; return ffp->is->audio_stream; + case FFP_PROP_INT64_VIDEO_DECODER: + if (!ffp) + return default_value; + return ffp->stat.vdec_type; + case FFP_PROP_INT64_AUDIO_DECODER: + return FFP_PROPV_DECODER_AVCODEC; + + case FFP_PROP_INT64_VIDEO_CACHED_DURATION: + if (!ffp) + return default_value; + return ffp->stat.video_cached_duration; + case FFP_PROP_INT64_AUDIO_CACHED_DURATION: + if (!ffp) + return default_value; + return ffp->stat.audio_cached_duration; + case FFP_PROP_INT64_VIDEO_CACHED_BYTES: + if (!ffp) + return default_value; + return ffp->stat.video_cached_bytes; + case FFP_PROP_INT64_AUDIO_CACHED_BYTES: + if (!ffp) + return default_value; + return ffp->stat.audio_cached_bytes; + case FFP_PROP_INT64_VIDEO_CACHED_PACKETS: + if (!ffp) + return default_value; + return ffp->stat.video_cached_packets; + case FFP_PROP_INT64_AUDIO_CACHED_PACKETS: + if (!ffp) + return default_value; + return ffp->stat.audio_cached_packets; default: return default_value; } diff --git a/ijkmedia/ijkplayer/ff_ffplay_def.h b/ijkmedia/ijkplayer/ff_ffplay_def.h index ae9f840cf7238e823c247e7ee23074c0dcc28dbe..85cbc73bc82681d00cabcc20e5f0370f996b8397 100644 --- a/ijkmedia/ijkplayer/ff_ffplay_def.h +++ b/ijkmedia/ijkplayer/ff_ffplay_def.h @@ -444,6 +444,22 @@ static SDL_Surface *screen; * end at line 330 in ffplay.c * near packet_queue_put ****************************************************************************/ +typedef struct FFStatistic +{ + int64_t vdec_type; + + float vfps; + float vdps; + float avdelay; + float avdiff; + + int64_t video_cached_duration; + int64_t audio_cached_duration; + int64_t video_cached_bytes; + int64_t audio_cached_bytes; + int64_t video_cached_packets; + int64_t audio_cached_packets; +} FFStatistic; /* ffplayer */ struct IjkMediaMeta; @@ -587,15 +603,14 @@ typedef struct FFPlayer { SDL_SpeedSampler vfps_sampler; SDL_SpeedSampler vdps_sampler; - float vfps; - float vdps; - /* filters */ SDL_mutex *vf_mutex; SDL_mutex *af_mutex; int vf_changed; int af_changed; float pf_playback_rate; + + FFStatistic stat; } FFPlayer; #define fftime_to_milliseconds(ts) (av_rescale(ts, 1000, AV_TIME_BASE)); @@ -704,15 +719,14 @@ inline static void ffp_reset_internal(FFPlayer *ffp) SDL_SpeedSamplerReset(&ffp->vfps_sampler); SDL_SpeedSamplerReset(&ffp->vdps_sampler); - ffp->vfps = 0.0f; - ffp->vdps = 0.0f; - /* filters */ ffp->vf_changed = 0; ffp->af_changed = 0; ffp->pf_playback_rate = 1.0f; msg_queue_flush(&ffp->msg_queue); + + memset(&ffp->stat, 0, sizeof(ffp->stat)); } inline static void ffp_notify_msg1(FFPlayer *ffp, int what) { diff --git a/ios/IJKMediaPlayer/IJKMediaPlayer.xcodeproj/project.pbxproj b/ios/IJKMediaPlayer/IJKMediaPlayer.xcodeproj/project.pbxproj index d46efe54734be07d5f53fcf080afca4dfe36df54..5ef67260b4f22263029b75b23c26997999dc7a74 100644 --- a/ios/IJKMediaPlayer/IJKMediaPlayer.xcodeproj/project.pbxproj +++ b/ios/IJKMediaPlayer/IJKMediaPlayer.xcodeproj/project.pbxproj @@ -70,6 +70,12 @@ E654EAEA1B6B295200B0F2D0 /* IJKFFMoviePlayerController.h in Headers */ = {isa = PBXBuildFile; fileRef = E66F8DE517EFD9C300354D80 /* IJKFFMoviePlayerController.h */; settings = {ATTRIBUTES = (Public, ); }; }; E654EAEC1B6B295200B0F2D0 /* IJKFFOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = E62139BC180FA89A00553533 /* IJKFFOptions.h */; settings = {ATTRIBUTES = (Public, ); }; }; E654EAED1B6B29C100B0F2D0 /* IJKMediaPlayer.h in Headers */ = {isa = PBXBuildFile; fileRef = E66F8DC217EECB1E00354D80 /* IJKMediaPlayer.h */; settings = {ATTRIBUTES = (Public, ); }; }; + E68B7AC51C1E7F20001DE241 /* IJKSDLHudViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = E68B7AC31C1E7F20001DE241 /* IJKSDLHudViewController.h */; }; + E68B7AC61C1E7F20001DE241 /* IJKSDLHudViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E68B7AC41C1E7F20001DE241 /* IJKSDLHudViewController.m */; }; + E68B7ACF1C1E97B0001DE241 /* IJKSDLHudViewCell.h in Headers */ = {isa = PBXBuildFile; fileRef = E68B7ACD1C1E97B0001DE241 /* IJKSDLHudViewCell.h */; }; + E68B7AD01C1E97B0001DE241 /* IJKSDLHudViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = E68B7ACE1C1E97B0001DE241 /* IJKSDLHudViewCell.m */; }; + E68B7ADA1C1FCA45001DE241 /* NSString+IJKMedia.h in Headers */ = {isa = PBXBuildFile; fileRef = E68B7AD81C1FCA45001DE241 /* NSString+IJKMedia.h */; }; + E68B7ADB1C1FCA45001DE241 /* NSString+IJKMedia.m in Sources */ = {isa = PBXBuildFile; fileRef = E68B7AD91C1FCA45001DE241 /* NSString+IJKMedia.m */; }; E69BE5511B93FED300AFBA3F /* allformats.c in Sources */ = {isa = PBXBuildFile; fileRef = E69BE54A1B93FED300AFBA3F /* allformats.c */; }; E69BE5531B93FED300AFBA3F /* async.c in Sources */ = {isa = PBXBuildFile; fileRef = E69BE54B1B93FED300AFBA3F /* async.c */; }; E69BE5561B93FED300AFBA3F /* ijkinject.c in Sources */ = {isa = PBXBuildFile; fileRef = E69BE54D1B93FED300AFBA3F /* ijkinject.c */; }; @@ -153,6 +159,12 @@ E67C4E0619D15EEA00415CEE /* IJKAVMoviePlayerController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IJKAVMoviePlayerController.h; path = IJKMediaPlayer/IJKAVMoviePlayerController.h; sourceTree = ""; }; E67C4E0719D15EEA00415CEE /* IJKAVMoviePlayerController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = IJKAVMoviePlayerController.m; path = IJKMediaPlayer/IJKAVMoviePlayerController.m; sourceTree = ""; }; E67FB4AC1B4A766F00AA94AA /* config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = config.h; sourceTree = ""; }; + E68B7AC31C1E7F20001DE241 /* IJKSDLHudViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJKSDLHudViewController.h; sourceTree = ""; }; + E68B7AC41C1E7F20001DE241 /* IJKSDLHudViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJKSDLHudViewController.m; sourceTree = ""; }; + E68B7ACD1C1E97B0001DE241 /* IJKSDLHudViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJKSDLHudViewCell.h; sourceTree = ""; }; + E68B7ACE1C1E97B0001DE241 /* IJKSDLHudViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJKSDLHudViewCell.m; sourceTree = ""; }; + E68B7AD81C1FCA45001DE241 /* NSString+IJKMedia.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+IJKMedia.h"; sourceTree = ""; }; + E68B7AD91C1FCA45001DE241 /* NSString+IJKMedia.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+IJKMedia.m"; sourceTree = ""; }; E69007F11B96E2A600EB346D /* url.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = url.h; sourceTree = ""; }; E6903EC017EAF6C500CFD954 /* IJKMediaPlayer-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "IJKMediaPlayer-Prefix.pch"; sourceTree = ""; }; E6903EC117EAF6C500CFD954 /* IJKMediaPlayback.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IJKMediaPlayback.h; path = IJKMediaPlayer/IJKMediaPlayback.h; sourceTree = ""; }; @@ -600,6 +612,10 @@ E6EE92B51878230C009EAB56 /* IJKSDLGLShader.m */, E6EE92B61878230C009EAB56 /* IJKSDLGLView.h */, E6EE92B71878230C009EAB56 /* IJKSDLGLView.m */, + E68B7AC31C1E7F20001DE241 /* IJKSDLHudViewController.h */, + E68B7AC41C1E7F20001DE241 /* IJKSDLHudViewController.m */, + E68B7ACD1C1E97B0001DE241 /* IJKSDLHudViewCell.h */, + E68B7ACE1C1E97B0001DE241 /* IJKSDLHudViewCell.m */, ); name = ios; path = ../../ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios; @@ -621,6 +637,8 @@ E6716E4A1807E5FC00B3FBC1 /* IJKMediaUtils.m */, E65DC3B719D93D5F004F8A08 /* IJKKVOController.h */, E65DC3B819D93D5F004F8A08 /* IJKKVOController.m */, + E68B7AD81C1FCA45001DE241 /* NSString+IJKMedia.h */, + E68B7AD91C1FCA45001DE241 /* NSString+IJKMedia.m */, ); name = IJKMediaPlayer; sourceTree = ""; @@ -632,6 +650,8 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + E68B7AC51C1E7F20001DE241 /* IJKSDLHudViewController.h in Headers */, + E68B7ADA1C1FCA45001DE241 /* NSString+IJKMedia.h in Headers */, E654EAE81B6B295200B0F2D0 /* IJKAVMoviePlayerController.h in Headers */, E654EAEA1B6B295200B0F2D0 /* IJKFFMoviePlayerController.h in Headers */, E654EAEC1B6B295200B0F2D0 /* IJKFFOptions.h in Headers */, @@ -642,6 +662,7 @@ E69BE5591B9405BD00AFBA3F /* ijkavformat.h in Headers */, E654EAED1B6B29C100B0F2D0 /* IJKMediaPlayer.h in Headers */, E654EAE91B6B295200B0F2D0 /* IJKMPMoviePlayerController.h in Headers */, + E68B7ACF1C1E97B0001DE241 /* IJKSDLHudViewCell.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -761,6 +782,7 @@ E607FFE11B7B62E3005F11A6 /* IJKDeviceModel.m in Sources */, E654EAA31B6B283700B0F2D0 /* IJKAudioKit.m in Sources */, E654EAAA1B6B284300B0F2D0 /* IJKMPMoviePlayerController.m in Sources */, + E68B7AD01C1E97B0001DE241 /* IJKSDLHudViewCell.m in Sources */, E654EACB1B6B288A00B0F2D0 /* ijksdl_vout_overlay_videotoolbox.m in Sources */, E654EAB11B6B285900B0F2D0 /* ff_ffpipenode.c in Sources */, E654EAC41B6B287E00B0F2D0 /* ijksdl_stdinc.c in Sources */, @@ -775,6 +797,7 @@ E654EAC31B6B287E00B0F2D0 /* ijksdl_mutex.c in Sources */, E654EACD1B6B288A00B0F2D0 /* IJKSDLAudioQueueController.m in Sources */, E654EAC51B6B287E00B0F2D0 /* ijksdl_thread.c in Sources */, + E68B7ADB1C1FCA45001DE241 /* NSString+IJKMedia.m in Sources */, E654EAB21B6B285900B0F2D0 /* ff_ffplay.c in Sources */, E654EAC01B6B287E00B0F2D0 /* ijksdl_aout.c in Sources */, E69BE5561B93FED300AFBA3F /* ijkinject.c in Sources */, @@ -794,6 +817,7 @@ E654EABE1B6B287400B0F2D0 /* image_convert.c in Sources */, E654EAB61B6B286400B0F2D0 /* ffpipenode_ios_videotoolbox_vdec.m in Sources */, E654EAA81B6B283D00B0F2D0 /* IJKAVPlayerLayerView.m in Sources */, + E68B7AC61C1E7F20001DE241 /* IJKSDLHudViewController.m in Sources */, E654EACA1B6B288A00B0F2D0 /* ijksdl_vout_ios_gles2.m in Sources */, E654EABA1B6B286B00B0F2D0 /* ffpipeline_ffplay.c in Sources */, ); diff --git a/ios/IJKMediaPlayer/IJKMediaPlayer/IJKFFMoviePlayerController.h b/ios/IJKMediaPlayer/IJKMediaPlayer/IJKFFMoviePlayerController.h index 1db6415fc6c7b102c15ab5018bf3d68d21148307..f192fe57a57b953dece91e5eec8c015d2c359ef0 100644 --- a/ios/IJKMediaPlayer/IJKMediaPlayer/IJKFFMoviePlayerController.h +++ b/ios/IJKMediaPlayer/IJKMediaPlayer/IJKFFMoviePlayerController.h @@ -94,6 +94,7 @@ typedef enum IJKLogLevel { @property(nonatomic, readonly) CGFloat fpsInMeta; @property(nonatomic, readonly) CGFloat fpsAtOutput; +@property(nonatomic) BOOL shouldShowHudView; - (void)setOptionValue:(NSString *)value forKey:(NSString *)key diff --git a/ios/IJKMediaPlayer/IJKMediaPlayer/IJKFFMoviePlayerController.m b/ios/IJKMediaPlayer/IJKMediaPlayer/IJKFFMoviePlayerController.m index b27e19661bfd5b7ab6e4ee4d4ab57c5bcabc3300..82d421021169b9f5b87e51cb993feb4f9d9e238f 100644 --- a/ios/IJKMediaPlayer/IJKMediaPlayer/IJKFFMoviePlayerController.m +++ b/ios/IJKMediaPlayer/IJKMediaPlayer/IJKFFMoviePlayerController.m @@ -27,6 +27,7 @@ #import "IJKMediaPlayback.h" #import "IJKMediaModule.h" #import "IJKAudioKit.h" +#import "NSString+IJKMedia.h" #include "string.h" #include "ijkplayer/version.h" @@ -63,6 +64,9 @@ static const char *kIJKFFRequiredFFmpegVersion = "ff2.8--ijk0.4.1.1--dev0.3.3--r BOOL _playingBeforeInterruption; NSMutableArray *_registeredNotifications; + + BOOL _shouldShowHudView; + NSTimer *_hudTimer; } @synthesize view = _view; @@ -175,6 +179,7 @@ void IJKFFIOStatCompleteRegister(void (*cb)(const char *url, // init fields _scalingMode = IJKMPMovieScalingModeAspectFit; _shouldAutoplay = YES; + _shouldShowHudView = options.showHudView; // init media resource _urlString = aUrlString; @@ -192,6 +197,10 @@ void IJKFFIOStatCompleteRegister(void (*cb)(const char *url, _glView = [[IJKSDLGLView alloc] initWithFrame:[[UIScreen mainScreen] bounds] useRenderQueue:options.useRenderQueue]; _view = _glView; + [_glView setHudValue:nil forKey:@"scheme"]; + [_glView setHudValue:nil forKey:@"host"]; + [_glView setHudValue:nil forKey:@"path"]; + [_glView setHudValue:nil forKey:@"ip"]; ijkmp_ios_set_glview(_mediaPlayer, _glView); ijkmp_set_option(_mediaPlayer, IJKMP_OPT_CATEGORY_PLAYER, "overlay-format", "fcc-i420"); @@ -247,6 +256,10 @@ void IJKFFIOStatCompleteRegister(void (*cb)(const char *url, if (!_mediaPlayer) return; + if (_urlString != nil) { + [self setHudUrl:_urlString]; + } + [self setScreenOn:_keepScreenOnWhilePlaying]; ijkmp_set_data_source(_mediaPlayer, [_urlString UTF8String]); @@ -254,6 +267,37 @@ void IJKFFIOStatCompleteRegister(void (*cb)(const char *url, ijkmp_prepare_async(_mediaPlayer); } +- (void)setHudUrl:(NSString *)urlString +{ + if ([[NSThread currentThread] isMainThread]) { + NSRange range = [urlString rangeOfString:@"://"]; + if (range.location != NSNotFound) { + NSString *urlFullScheme = [urlString substringToIndex:range.location]; + + NSRange rangeOfLastScheme = [urlFullScheme rangeOfString:@":" + options:NSBackwardsSearch + range:NSMakeRange(0, range.location)]; + if (rangeOfLastScheme.location != NSNotFound) { + NSString *urlExtra = [urlString substringFromIndex:rangeOfLastScheme.location + 1]; + NSURL *url = [NSURL URLWithString:urlExtra]; + [_glView setHudValue:urlFullScheme forKey:@"scheme"]; + [_glView setHudValue:url.host forKey:@"host"]; + [_glView setHudValue:url.path forKey:@"path"]; + return; + } + } + + NSURL *url = [NSURL URLWithString:urlString]; + [_glView setHudValue:url.scheme forKey:@"scheme"]; + [_glView setHudValue:url.host forKey:@"host"]; + [_glView setHudValue:url.path forKey:@"path"]; + } else { + dispatch_async(dispatch_get_main_queue(), ^{ + [self setHudUrl:urlString]; + }); + } +} + - (void)play { if (!_mediaPlayer) @@ -261,6 +305,7 @@ void IJKFFIOStatCompleteRegister(void (*cb)(const char *url, [self setScreenOn:_keepScreenOnWhilePlaying]; + [self startHudTimer]; ijkmp_start(_mediaPlayer); } @@ -269,6 +314,7 @@ void IJKFFIOStatCompleteRegister(void (*cb)(const char *url, if (!_mediaPlayer) return; + [self stopHudTimer]; ijkmp_pause(_mediaPlayer); } @@ -279,6 +325,7 @@ void IJKFFIOStatCompleteRegister(void (*cb)(const char *url, [self setScreenOn:NO]; + [self stopHudTimer]; ijkmp_stop(_mediaPlayer); } @@ -405,6 +452,8 @@ inline static int getPlayerOption(IJKFFOptionCategory category) { if (!_mediaPlayer) return; + + [self stopHudTimer]; [self unregisterApplicationObservers]; [self setScreenOn:NO]; @@ -579,6 +628,99 @@ inline static int getPlayerOption(IJKFFOptionCategory category) return _glView.fps; } +- (void)refreshHudView +{ + if (_mediaPlayer == nil) + return; + + int64_t vdec = ijkmp_get_property_int64(_mediaPlayer, FFP_PROP_INT64_VIDEO_DECODER, FFP_PROPV_DECODER_UNKNOWN); + float vdps = ijkmp_get_property_float(_mediaPlayer, FFP_PROP_FLOAT_VIDEO_DECODE_FRAMES_PER_SECOND, .0f); + float vfps = ijkmp_get_property_float(_mediaPlayer, FFP_PROP_FLOAT_VIDEO_OUTPUT_FRAMES_PER_SECOND, .0f); + + switch (vdec) { + case FFP_PROPV_DECODER_VIDEOTOOLBOX: + [_glView setHudValue:@"VideoToolbox" forKey:@"vdec"]; + break; + case FFP_PROPV_DECODER_AVCODEC: + [_glView setHudValue:[NSString stringWithFormat:@"avcodec %d.%d.%d", + LIBAVCODEC_VERSION_MAJOR, + LIBAVCODEC_VERSION_MINOR, + LIBAVCODEC_VERSION_MICRO] + forKey:@"vdec"]; + break; + default: + [_glView setHudValue:@"N/A" forKey:@"vdec"]; + break; + } + + [_glView setHudValue:[NSString stringWithFormat:@"%.2f / %.2f", vdps, vfps] forKey:@"fps"]; + + int64_t vcacheb = ijkmp_get_property_int64(_mediaPlayer, FFP_PROP_INT64_VIDEO_CACHED_BYTES, 0); + int64_t acacheb = ijkmp_get_property_int64(_mediaPlayer, FFP_PROP_INT64_AUDIO_CACHED_BYTES, 0); + int64_t vcached = ijkmp_get_property_int64(_mediaPlayer, FFP_PROP_INT64_VIDEO_CACHED_DURATION, 0); + int64_t acached = ijkmp_get_property_int64(_mediaPlayer, FFP_PROP_INT64_AUDIO_CACHED_DURATION, 0); + int64_t vcachep = ijkmp_get_property_int64(_mediaPlayer, FFP_PROP_INT64_VIDEO_CACHED_PACKETS, 0); + int64_t acachep = ijkmp_get_property_int64(_mediaPlayer, FFP_PROP_INT64_AUDIO_CACHED_PACKETS, 0); + [_glView setHudValue:[NSString stringWithFormat:@"%"PRId64" ms, %"PRId64" bytes, %"PRId64" packets", vcached, vcacheb, vcachep] + forKey:@"v-cache"]; + [_glView setHudValue:[NSString stringWithFormat:@"%"PRId64" ms, %"PRId64" bytes, %"PRId64" packets", acached, acacheb, acachep] + forKey:@"a-cache"]; + + float avdelay = ijkmp_get_property_float(_mediaPlayer, FFP_PROP_FLOAT_AVDELAY, .0f); + float avdiff = ijkmp_get_property_float(_mediaPlayer, FFP_PROP_FLOAT_AVDIFF, .0f); + [_glView setHudValue:[NSString stringWithFormat:@"%.3f %.3f", avdelay, -avdiff] forKey:@"delay"]; +} + +- (void)startHudTimer +{ + if (!_shouldShowHudView) + return; + + if (_hudTimer != nil) + return; + + if ([[NSThread currentThread] isMainThread]) { + _hudTimer = [NSTimer scheduledTimerWithTimeInterval:.5f + target:self + selector:@selector(refreshHudView) + userInfo:nil + repeats:YES]; + } else { + dispatch_async(dispatch_get_main_queue(), ^{ + [self startHudTimer]; + }); + } +} + +- (void)stopHudTimer +{ + if (_hudTimer == nil) + return; + + if ([[NSThread currentThread] isMainThread]) { + [_hudTimer invalidate]; + _hudTimer = nil; + } else { + dispatch_async(dispatch_get_main_queue(), ^{ + [self stopHudTimer]; + }); + } +} + +- (void)setShouldShowHudView:(BOOL)shouldShowHudView +{ + _shouldShowHudView = shouldShowHudView; + if (shouldShowHudView) + [self startHudTimer]; + else + [self stopHudTimer]; +} + +- (BOOL)shouldShowHudView +{ + return _shouldShowHudView; +} + - (void)setPlaybackRate:(float)playbackRate { if (!_mediaPlayer) @@ -715,6 +857,7 @@ inline static void fillMetaInternal(NSMutableDictionary *meta, IjkMediaMeta *raw _mediaMeta = newMediaMeta; } + [self startHudTimer]; _isPreparedToPlay = YES; [[NSNotificationCenter defaultCenter] postNotificationName:IJKMPMediaPlaybackIsPreparedToPlayDidChangeNotification object:self]; @@ -871,7 +1014,7 @@ int media_player_msg_loop(void* arg) #pragma mark av_format_control_message -static int onInjectUrlOpen(id delegate, int type, void *data, size_t data_size) +static int onInjectUrlOpen(IJKFFMoviePlayerController *mpc, id delegate, int type, void *data, size_t data_size) { IJKAVInject_OnUrlOpenData *realData = data; assert(realData); @@ -882,8 +1025,18 @@ static int onInjectUrlOpen(id delegate, int type, void if (delegate == nil) return 0; + NSString *urlString = [NSString stringWithUTF8String:realData->url]; + NSURL *url = [NSURL URLWithString:urlString]; + if ([url.scheme isEqualToString:@"tcp"] || [url.scheme isEqualToString:@"udp"]) { + if ([url.host ijk_isIpv4]) { + [mpc->_glView setHudValue:url.host forKey:@"ip"]; + } + } else { + [mpc setHudUrl:urlString]; + } + IJKMediaUrlOpenData *openData = - [[IJKMediaUrlOpenData alloc] initWithUrl:[NSString stringWithUTF8String:realData->url] + [[IJKMediaUrlOpenData alloc] initWithUrl:urlString openType:(IJKMediaUrlOpenType)type segmentIndex:realData->segment_index retryCounter:realData->retry_counter]; @@ -912,13 +1065,13 @@ static int ijkff_inject_callback(void *opaque, int message, void *data, size_t d switch (message) { case IJKAVINJECT_CONCAT_RESOLVE_SEGMENT: - return onInjectUrlOpen(mpc.segmentOpenDelegate, message, data, data_size); + return onInjectUrlOpen(mpc, mpc.segmentOpenDelegate, message, data, data_size); case IJKAVINJECT_ON_TCP_OPEN: - return onInjectUrlOpen(mpc.tcpOpenDelegate, message, data, data_size); + return onInjectUrlOpen(mpc, mpc.tcpOpenDelegate, message, data, data_size); case IJKAVINJECT_ON_HTTP_OPEN: - return onInjectUrlOpen(mpc.httpOpenDelegate, message, data, data_size); + return onInjectUrlOpen(mpc, mpc.httpOpenDelegate, message, data, data_size); case IJKAVINJECT_ON_LIVE_RETRY: - return onInjectUrlOpen(mpc.liveOpenDelegate, message, data, data_size); + return onInjectUrlOpen(mpc, mpc.liveOpenDelegate, message, data, data_size); default: { return 0; } diff --git a/ios/IJKMediaPlayer/IJKMediaPlayer/IJKFFOptions.h b/ios/IJKMediaPlayer/IJKMediaPlayer/IJKFFOptions.h index cb66f49808098572c977dd33bc09ae2544c382ba..22030e5a5ff29162ea428da7f3fcaff7b58cb556 100644 --- a/ios/IJKMediaPlayer/IJKMediaPlayer/IJKFFOptions.h +++ b/ios/IJKMediaPlayer/IJKMediaPlayer/IJKFFOptions.h @@ -69,5 +69,6 @@ struct IjkMediaPlayer; -(void)setPlayerOptionIntValue: (int64_t)value forKey:(NSString *)key; @property(nonatomic) BOOL useRenderQueue; +@property(nonatomic) BOOL showHudView; @end diff --git a/ios/IJKMediaPlayer/IJKMediaPlayer/IJKFFOptions.m b/ios/IJKMediaPlayer/IJKMediaPlayer/IJKFFOptions.m index c2180dcbb49f8635cdce68d8f14d00182dbe445b..74830f4c0e9820c7a7b7fc0ea0bbf6b5b81611f1 100644 --- a/ios/IJKMediaPlayer/IJKMediaPlayer/IJKFFOptions.m +++ b/ios/IJKMediaPlayer/IJKMediaPlayer/IJKFFOptions.m @@ -51,6 +51,7 @@ [options setCodecOptionIntValue:IJK_AVDISCARD_NONREF forKey:@"skip_frame"]; options.useRenderQueue = NO; + options.showHudView = NO; return options; } diff --git a/ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijkplayer/ios/pipeline/IJKVideoToolBox.m b/ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijkplayer/ios/pipeline/IJKVideoToolBox.m index 43263b6d65aa8b3e8e788db57fc8473803f562a8..1fa071cf5f2271e79110f8a62967e16cc152e1ad 100644 --- a/ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijkplayer/ios/pipeline/IJKVideoToolBox.m +++ b/ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijkplayer/ios/pipeline/IJKVideoToolBox.m @@ -327,7 +327,7 @@ void VTDecoderCallback(void *decompressionOutputRefCon, goto failed; } - ffp->vdps = SDL_SpeedSamplerAdd(&ctx->sampler, FFP_SHOW_VDPS_VIDEOTOOLBOX, "vdps[VideoToolbox]"); + ffp->stat.vdps = SDL_SpeedSamplerAdd(&ctx->sampler, FFP_SHOW_VDPS_VIDEOTOOLBOX, "vdps[VideoToolbox]"); #ifdef FFP_VTB_DISABLE_OUTPUT goto failed; #endif diff --git a/ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijkplayer/ios/pipeline/ffpipeline_ios.c b/ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijkplayer/ios/pipeline/ffpipeline_ios.c index 44cfa204c92b4299c6a54aab5afe05ba70a110c7..631684d8c4f82eee15e079af7a13bada88af1923 100644 --- a/ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijkplayer/ios/pipeline/ffpipeline_ios.c +++ b/ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijkplayer/ios/pipeline/ffpipeline_ios.c @@ -45,8 +45,10 @@ static IJKFF_Pipenode *func_open_video_decoder(IJKFF_Pipeline *pipeline, FFPlaye if (node == NULL) { ALOGE("vtb fail!!! switch to ffmpeg decode!!!! \n"); node = ffpipenode_create_video_decoder_from_ffplay(ffp); + ffp->stat.vdec_type = FFP_PROPV_DECODER_AVCODEC; opaque->is_videotoolbox_open = false; } else { + ffp->stat.vdec_type = FFP_PROPV_DECODER_VIDEOTOOLBOX; opaque->is_videotoolbox_open = true; } ffp_notify_msg2(ffp, FFP_MSG_VIDEO_DECODER_OPEN, opaque->is_videotoolbox_open); diff --git a/ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/IJKSDLGLView.h b/ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/IJKSDLGLView.h index ab96b8fc197e23dab42d771f09e1b4a0c00d5eeb..e50242bcb138859a5763ab366a5399b0633b0610 100644 --- a/ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/IJKSDLGLView.h +++ b/ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/IJKSDLGLView.h @@ -32,9 +32,11 @@ - (void) display: (SDL_VoutOverlay *) overlay; - (UIImage*) snapshot; +- (void)setHudValue:(NSString *)value forKey:(NSString *)key; @property(nonatomic,strong) NSLock *appActivityLock; @property(nonatomic) CGFloat fps; @property(nonatomic) CGFloat scaleFactor; +@property(nonatomic) BOOL shouldShowHudView; @end diff --git a/ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/IJKSDLGLView.m b/ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/IJKSDLGLView.m index 686316833732246f0da075e8798eef57eecc11c0..f8b78965ed9e9a2354f2892aade323961c8014f8 100644 --- a/ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/IJKSDLGLView.m +++ b/ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/IJKSDLGLView.m @@ -30,7 +30,7 @@ #import "IJKSDLGLRenderNV12.h" #include "ijksdl/ijksdl_timer.h" #include "ijksdl/ios/ijksdl_ios.h" - +#import "IJKSDLHudViewController.h" static NSString *const g_vertexShaderString = IJK_SHADER_STRING ( @@ -184,6 +184,8 @@ static void mat4f_LoadOrtho(float left, float right, float bottom, float top, fl BOOL _useRenderQueue; dispatch_queue_t _renderQueue; + + IJKSDLHudViewController *_hudViewController; } enum { @@ -225,6 +227,9 @@ static int g_ijk_gles_queue_spec_key; _didSetupGL = NO; [self setupGLOnce]; + + _hudViewController = [[IJKSDLHudViewController alloc] init]; + [self addSubview:_hudViewController.tableView]; } return self; @@ -411,6 +416,19 @@ static int g_ijk_gles_queue_spec_key; - (void)layoutSubviews { + [super layoutSubviews]; + + CGRect selfFrame = self.frame; + CGRect newFrame = selfFrame; + + newFrame.size.width = selfFrame.size.width * 1 / 3; + newFrame.origin.x = selfFrame.size.width * 2 / 3; + + newFrame.size.height = selfFrame.size.height * 6 / 8; + newFrame.origin.y += selfFrame.size.height * 1 / 8; + + _hudViewController.tableView.frame = newFrame; + _didRelayoutSubViews = YES; } @@ -930,4 +948,26 @@ exit: return image; } +#pragma mark IJKFFHudController +- (void)setHudValue:(NSString *)value forKey:(NSString *)key +{ + if ([[NSThread currentThread] isMainThread]) { + [_hudViewController setHudValue:value forKey:key]; + } else { + dispatch_async(dispatch_get_main_queue(), ^{ + [self setHudValue:value forKey:key]; + }); + } +} + +- (void)setShouldShowHudView:(BOOL)shouldShowHudView +{ + _hudViewController.tableView.hidden = !shouldShowHudView; +} + +- (BOOL)shouldShowHudView +{ + return !_hudViewController.tableView.hidden; +} + @end diff --git a/ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/IJKSDLHudViewCell.h b/ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/IJKSDLHudViewCell.h new file mode 100644 index 0000000000000000000000000000000000000000..ce093f824a13969747a927324d7c166c299703ba --- /dev/null +++ b/ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/IJKSDLHudViewCell.h @@ -0,0 +1,17 @@ +// +// IJKSDLHudViewCell.h +// IJKMediaPlayer +// +// Created by Zhang Rui on 15/12/14. +// Copyright © 2015年 bilibili. All rights reserved. +// + +#import + +@interface IJKSDLHudViewCell : UITableViewCell + +- (id)init; + +- (void)setHudValue:(NSString *)value forKey:(NSString *)key; + +@end diff --git a/ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/IJKSDLHudViewCell.m b/ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/IJKSDLHudViewCell.m new file mode 100644 index 0000000000000000000000000000000000000000..f46413d6b580bea26a0a885c25f03b77bca36677 --- /dev/null +++ b/ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/IJKSDLHudViewCell.m @@ -0,0 +1,65 @@ +// +// IJKSDLHudViewCell.m +// IJKMediaPlayer +// +// Created by Zhang Rui on 15/12/14. +// Copyright © 2015年 bilibili. All rights reserved. +// + +#import "IJKSDLHudViewCell.h" + +#define COLUMN_COUNT 2 +#define CELL_MARGIN 8 + +@interface IJKSDLHudViewCell() + +@end + +@implementation IJKSDLHudViewCell +{ + UILabel *_column[COLUMN_COUNT]; +} + +- (id)init +{ + self = [super init]; + if (self) { + self.backgroundColor = [UIColor clearColor]; + self.contentView.backgroundColor = [UIColor clearColor]; + + for (int i = 0; i < COLUMN_COUNT; ++i) { + _column[i] = [[UILabel alloc] init]; + _column[i].textColor = [UIColor whiteColor]; + _column[i].font = [UIFont fontWithName:@"Menlo" size:9]; + + [self.contentView addSubview:_column[i]]; + } + } + return self; +} + +- (void)setHudValue:(NSString *)value forKey:(NSString *)key +{ + _column[0].text = key; + _column[1].text = value; +} + +- (void)layoutSubviews +{ + [super layoutSubviews]; + + CGRect parentFrame = self.contentView.frame; + CGRect newFrame = parentFrame; + CGFloat nextX = CELL_MARGIN; + + newFrame.origin.x = nextX; + newFrame.size.width = parentFrame.size.width * 0.2; + _column[0].frame = newFrame; + nextX = newFrame.origin.x + newFrame.size.width + CELL_MARGIN; + + newFrame.origin.x = nextX; + newFrame.size.width = parentFrame.size.width - nextX - CELL_MARGIN; + _column[1].frame = newFrame; +} + +@end diff --git a/ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/IJKSDLHudViewController.h b/ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/IJKSDLHudViewController.h new file mode 100644 index 0000000000000000000000000000000000000000..05af3b7ba703590243cbde7440b4f860d8a39328 --- /dev/null +++ b/ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/IJKSDLHudViewController.h @@ -0,0 +1,17 @@ +// +// IJKSDLHudViewController.h +// IJKMediaPlayer +// +// Created by Zhang Rui on 15/12/14. +// Copyright © 2015年 bilibili. All rights reserved. +// + +#import + +@interface IJKSDLHudViewController : UITableViewController + +- (id)init; + +- (void)setHudValue:(NSString *)value forKey:(NSString *)key; + +@end diff --git a/ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/IJKSDLHudViewController.m b/ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/IJKSDLHudViewController.m new file mode 100644 index 0000000000000000000000000000000000000000..d18e44cb7c4fdac201a7580e1b999164975dd885 --- /dev/null +++ b/ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/IJKSDLHudViewController.m @@ -0,0 +1,93 @@ +// +// IJKSDLHudViewController.m +// IJKMediaPlayer +// +// Created by Zhang Rui on 15/12/14. +// Copyright © 2015年 bilibili. All rights reserved. +// + +#import "IJKSDLHudViewController.h" +#import "IJKSDLHudViewCell.h" + +@interface HudViewCellData : NSObject +@property(nonatomic) NSString *key; +@property(nonatomic) NSString *value; +@end + +@implementation HudViewCellData +@end + +@interface IJKSDLHudViewController() + +@end + +@implementation IJKSDLHudViewController +{ + NSMutableDictionary *_keyIndexes; + NSMutableArray *_hudDataArray; +} + +- (id)init +{ + self = [super init]; + if (self) { + _keyIndexes = [[NSMutableDictionary alloc] init]; + _hudDataArray = [[NSMutableArray alloc] init]; + + self.tableView.backgroundColor = [[UIColor alloc] initWithRed:.5f green:.5f blue:.5f alpha:.5f]; + self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; + } + return self; +} + +- (void)setHudValue:(NSString *)value forKey:(NSString *)key +{ + HudViewCellData *data = nil; + NSNumber *index = [_keyIndexes objectForKey:key]; + if (index == nil) { + data = [[HudViewCellData alloc] init]; + data.key = key; + [_keyIndexes setObject:[NSNumber numberWithUnsignedInteger:_hudDataArray.count] + forKey:key]; + [_hudDataArray addObject:data]; + } else { + data = [_hudDataArray objectAtIndex:[index unsignedIntegerValue]]; + } + + data.value = value; + [self.tableView reloadData]; +} + +#pragma mark UITableViewDataSource + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section +{ + assert(section == 0); + return _hudDataArray.count; +} + +- (UITableViewCell *)tableView:(UITableView *)tableView + cellForRowAtIndexPath:(NSIndexPath *)indexPath +{ + assert(indexPath.section == 0); + + IJKSDLHudViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"hud"]; + if (cell == nil) { + cell = [[IJKSDLHudViewCell alloc] init]; + } + + HudViewCellData *data = [_hudDataArray objectAtIndex:indexPath.item]; + + [cell setHudValue:data.value forKey:data.key]; + + return cell; +} + +#pragma mark UITableViewDelegate + +- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath +{ + return 20.f; +} + +@end diff --git a/ios/IJKMediaPlayer/NSString+IJKMedia.h b/ios/IJKMediaPlayer/NSString+IJKMedia.h new file mode 100644 index 0000000000000000000000000000000000000000..e9fa4844b90aaf0dfe2b64a30d2702eb2edba099 --- /dev/null +++ b/ios/IJKMediaPlayer/NSString+IJKMedia.h @@ -0,0 +1,15 @@ +// +// NSString+IJKMedia.h +// IJKMediaPlayer +// +// Created by Zhang Rui on 15/12/15. +// Copyright © 2015年 bilibili. All rights reserved. +// + +#import + +@interface NSString (IJKMedia) + +- (BOOL) ijk_isIpv4; + +@end diff --git a/ios/IJKMediaPlayer/NSString+IJKMedia.m b/ios/IJKMediaPlayer/NSString+IJKMedia.m new file mode 100644 index 0000000000000000000000000000000000000000..4a35b9bbda266250b923440451e89fa3d63cc56c --- /dev/null +++ b/ios/IJKMediaPlayer/NSString+IJKMedia.m @@ -0,0 +1,22 @@ +// +// NSString+IJKMedia.m +// IJKMediaPlayer +// +// Created by Zhang Rui on 15/12/15. +// Copyright © 2015年 bilibili. All rights reserved. +// + +#import "NSString+IJKMedia.h" + +@implementation NSString (IJKMedia) + +- (BOOL) ijk_isIpv4 +{ + NSString *regexp = + @"^(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])\\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])$"; + + NSRange range = [self rangeOfString:regexp options:NSRegularExpressionSearch]; + return range.location != NSNotFound; +} + +@end