diff --git a/ijkmedia/ijkplayer/ff_ffplay.c b/ijkmedia/ijkplayer/ff_ffplay.c index 6ba2f3db19..925f9aa8a7 100755 --- a/ijkmedia/ijkplayer/ff_ffplay.c +++ b/ijkmedia/ijkplayer/ff_ffplay.c @@ -658,6 +658,19 @@ static int decoder_decode_frame(FFPlayer *ffp, Decoder *d, AVFrame *frame, AVSub } } while (d->queue->serial != d->pkt_serial); +// if (!ffp->is_first && pkt.pts == pkt.dts) { +// ffp->start_pts = pkt.pts; +// ffp->start_dts = pkt.dts; +// } + +// if (ffp->is_record) { +// if (0 != ffp_record_file(ffp, &pkt)) { +// ffp->record_error = 1; +// ffp_stop_recording_l(ffp); +// printf("avcodec_send_packet stop\n"); +// } +// } + if (pkt.data == flush_pkt.data) { avcodec_flush_buffers(d->avctx); d->finished = 0; @@ -3099,6 +3112,167 @@ static int is_realtime(AVFormatContext *s) return 0; } +int ffp_start_recording_l(FFPlayer *ffp, const char *file_name) +{ + assert(ffp); + VideoState *is = ffp->is; + + ffp->m_ofmt_ctx = NULL; + ffp->m_ofmt = NULL; + ffp->is_record = 0; + ffp->record_error = 0; + + if (!file_name || !strlen(file_name)) { + av_log(ffp, AV_LOG_ERROR, "filename is invalid"); + goto end; + } + + if (!is || !is->ic || is->paused || is->abort_request) { + av_log(ffp, AV_LOG_ERROR, "is,is->ic,is->paused is invalid"); + goto end; + } + + + av_log(ffp->is_record, AV_LOG_DEBUG, "NHATHM ------"); + if (ffp->is_record) { + av_log(ffp, AV_LOG_ERROR, "recording has started"); + av_log(ffp->is_record, AV_LOG_DEBUG, "NHATHM ------ 2"); + goto end; + } + + avformat_alloc_output_context2(&ffp->m_ofmt_ctx, NULL, NULL, file_name); + if (!ffp->m_ofmt_ctx) { + av_log(ffp, AV_LOG_ERROR, "Could not create output context filename is %s\n", file_name); + goto end; + } + ffp->m_ofmt = ffp->m_ofmt_ctx->oformat; + + for (int i = 0; i < is->ic->nb_streams; i++) { + AVStream *in_stream = is->ic->streams[i]; + AVStream *out_stream = avformat_new_stream(ffp->m_ofmt_ctx, in_stream->codec->codec); + if (!out_stream) { + av_log(ffp, AV_LOG_ERROR, "Failed allocating output stream\n"); + goto end; + } + + av_log(ffp, AV_LOG_DEBUG, "in_stream->codec;%p\n", in_stream->codec); + if (avcodec_copy_context(out_stream->codec, in_stream->codec) < 0) { + av_log(ffp, AV_LOG_ERROR, "Failed to copy context from input to output stream codec context\n"); + goto end; + } + + out_stream->codec->codec_tag = 0; + if (ffp->m_ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER) { + out_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER; + } + } + + av_dump_format(ffp->m_ofmt_ctx, 0, file_name, 1); + + if (!(ffp->m_ofmt->flags & AVFMT_NOFILE)) { + if (avio_open(&ffp->m_ofmt_ctx->pb, file_name, AVIO_FLAG_WRITE) < 0) { + av_log(ffp, AV_LOG_ERROR, "Could not open output file '%s'", file_name); + goto end; + } + } + + if (avformat_write_header(ffp->m_ofmt_ctx, NULL) < 0) { + av_log(ffp, AV_LOG_ERROR, "Error occurred when opening output file\n"); + goto end; + } + + ffp->is_record = 1; + ffp->record_error = 0; + pthread_mutex_init(&ffp->record_mutex, NULL); + + return 0; +end: + ffp->record_error = 1; + return -1; +} + +int ffp_record_isfinished_l(FFPlayer *ffp) +{ + return 0; +} + +int ffp_record_file(FFPlayer *ffp, AVPacket *packet) +{ + assert(ffp); + VideoState *is = ffp->is; + int ret = 0; + AVStream *in_stream; + AVStream *out_stream; + + if (ffp->is_record) { + if (packet == NULL) { + ffp->record_error = 1; + av_log(ffp, AV_LOG_ERROR, "packet == NULL"); + return -1; + } + + AVPacket *pkt = (AVPacket *)av_malloc(sizeof(AVPacket)); + av_new_packet(pkt, 0); + if (0 == av_packet_ref(pkt, packet)) { + pthread_mutex_lock(&ffp->record_mutex); + if (!ffp->is_first) { + ffp->is_first = 1; + pkt->pts = 0; + pkt->dts = 0; + } else { + if (pkt->stream_index == AVMEDIA_TYPE_AUDIO) { + pkt->pts = llabs(pkt->pts - ffp->start_a_pts); + pkt->dts = llabs(pkt->dts - ffp->start_a_dts); + } + else if (pkt->stream_index == AVMEDIA_TYPE_VIDEO) { + pkt->pts = pkt->dts = llabs(pkt->dts - ffp->start_v_dts); + } + } + + in_stream = is->ic->streams[pkt->stream_index]; + out_stream = ffp->m_ofmt_ctx->streams[pkt->stream_index]; + + pkt->pts = av_rescale_q_rnd(pkt->pts, in_stream->time_base, out_stream->time_base, (AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX)); + pkt->dts = av_rescale_q_rnd(pkt->dts, in_stream->time_base, out_stream->time_base, (AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX)); + pkt->duration = av_rescale_q(pkt->duration, in_stream->time_base, out_stream->time_base); + pkt->pos = -1; + + if ((ret = av_interleaved_write_frame(ffp->m_ofmt_ctx, pkt)) < 0) { + av_log(ffp, AV_LOG_ERROR, "Error muxing packet\n"); + } + + av_packet_unref(pkt); + pthread_mutex_unlock(&ffp->record_mutex); + } else { + av_log(ffp, AV_LOG_ERROR, "av_packet_ref == NULL"); + } + } + return ret; +} + +int ffp_stop_recording_l(FFPlayer *ffp){ + assert(ffp); + if (ffp->is_record) { + ffp->is_record = 0; + pthread_mutex_lock(&ffp->record_mutex); + if (ffp->m_ofmt_ctx != NULL) { + av_write_trailer(ffp->m_ofmt_ctx); + if (ffp->m_ofmt_ctx && !(ffp->m_ofmt->flags & AVFMT_NOFILE)) { + avio_close(ffp->m_ofmt_ctx->pb); + } + avformat_free_context(ffp->m_ofmt_ctx); + ffp->m_ofmt_ctx = NULL; + ffp->is_first = 0; + } + pthread_mutex_unlock(&ffp->record_mutex); + pthread_mutex_destroy(&ffp->record_mutex); + av_log(ffp, AV_LOG_DEBUG, "stopRecord ok\n"); + } else { + av_log(ffp, AV_LOG_ERROR, "don't need stopRecord\n"); + } + return 0; +} + /* this thread gets the stream from the disk or the network */ static int read_thread(void *arg) { @@ -3392,6 +3566,26 @@ static int read_thread(void *arg) } for (;;) { + if (!ffp->is_first && pkt->pts == pkt->dts) { + if (pkt->stream_index == AVMEDIA_TYPE_AUDIO) { + ffp->start_a_pts = pkt->pts; + ffp->start_a_dts = pkt->dts; + } + } + if (pkt->stream_index == AVMEDIA_TYPE_VIDEO) { + if (!ffp->is_first) { + ffp->start_v_pts = pkt->pts; + ffp->start_v_dts = pkt->dts; + } + } + + if (ffp->is_record) { + if (0 != ffp_record_file(ffp, pkt)) { + ffp->record_error = 1; + ffp_stop_recording_l(ffp); + } + } + if (is->abort_request) break; #ifdef FFP_MERGE diff --git a/ijkmedia/ijkplayer/ff_ffplay.h b/ijkmedia/ijkplayer/ff_ffplay.h index ae21398272..9498356e8f 100644 --- a/ijkmedia/ijkplayer/ff_ffplay.h +++ b/ijkmedia/ijkplayer/ff_ffplay.h @@ -64,6 +64,11 @@ int ffp_is_paused_l(FFPlayer *ffp); int ffp_stop_l(FFPlayer *ffp); int ffp_wait_stop_l(FFPlayer *ffp); +/* record rtsp streaming */ +int ffp_start_recording_l(FFPlayer *ffp, const char *file_name); +int ffp_record_isfinished_l(FFPlayer *ffp); +int ffp_stop_recording_l(FFPlayer *ffp); + /* all in milliseconds */ int ffp_seek_to_l(FFPlayer *ffp, long msec); long ffp_get_current_position_l(FFPlayer *ffp); diff --git a/ijkmedia/ijkplayer/ff_ffplay_def.h b/ijkmedia/ijkplayer/ff_ffplay_def.h index e9dc920de9..f3ae86e25f 100755 --- a/ijkmedia/ijkplayer/ff_ffplay_def.h +++ b/ijkmedia/ijkplayer/ff_ffplay_def.h @@ -720,6 +720,17 @@ typedef struct FFPlayer { char *mediacodec_default_name; int ijkmeta_delay_init; int render_wait_start; + + AVFormatContext *m_ofmt_ctx; + AVOutputFormat *m_ofmt; + pthread_mutex_t record_mutex; + int is_record; + int record_error; + int is_first; + int64_t start_v_pts; + int64_t start_v_dts; + int64_t start_a_pts; + int64_t start_a_dts; } FFPlayer; #define fftime_to_milliseconds(ts) (av_rescale(ts, 1000, AV_TIME_BASE)) diff --git a/ijkmedia/ijkplayer/ijkplayer.c b/ijkmedia/ijkplayer/ijkplayer.c index 8ea4d4748e..25d338b8cf 100755 --- a/ijkmedia/ijkplayer/ijkplayer.c +++ b/ijkmedia/ijkplayer/ijkplayer.c @@ -796,3 +796,54 @@ int ijkmp_get_msg(IjkMediaPlayer *mp, AVMessage *msg, int block) return -1; } + +static int ijkmp_start_recording_l(IjkMediaPlayer *mp, const char *filePath) +{ + av_log(mp->ffplayer,AV_LOG_INFO,"cjz ijkmp_start_recording_l filePath %s",filePath); + return ffp_start_recording_l(mp->ffplayer, filePath); +} + +int ijkmp_start_recording(IjkMediaPlayer *mp,const char *filePath) +{ + assert(mp); + pthread_mutex_lock(&mp->mutex); + av_log(mp->ffplayer,AV_LOG_WARNING,"cjz ijkmp_start_recording --- "); + int retval = ijkmp_start_recording_l(mp,filePath); + printf("ijkmp_start_recording return == %d\n",retval); + pthread_mutex_unlock(&mp->mutex); + return retval; +} + +static int ijkmp_stop_recording_l(IjkMediaPlayer *mp) +{ + return ffp_stop_recording_l(mp->ffplayer); +} + +int ijkmp_stop_recording(IjkMediaPlayer *mp) +{ + assert(mp); + pthread_mutex_lock(&mp->mutex); + av_log(mp->ffplayer,AV_LOG_WARNING,"cjz ijkmp_stop_recording"); + int retval = ijkmp_stop_recording_l(mp); + pthread_mutex_unlock(&mp->mutex); + return retval; +} + +static int ijkmp_isRecordFinished_l(IjkMediaPlayer *mp) +{ + return ffp_record_isfinished_l(mp->ffplayer); +} + +int ijkmp_isRecordFinished(IjkMediaPlayer *mp) +{ + assert(mp); + pthread_mutex_lock(&mp->mutex); + av_log(mp->ffplayer,AV_LOG_WARNING,"cjz ijkmp_isRecordFinished "); + int retval = ijkmp_isRecordFinished_l(mp); + pthread_mutex_unlock(&mp->mutex); + return retval; +} + +int ijkmp_isRecording(IjkMediaPlayer *mp) { + return mp->ffplayer->is_record; +} diff --git a/ijkmedia/ijkplayer/ijkplayer.h b/ijkmedia/ijkplayer/ijkplayer.h index 9e99883dea..a3a352997d 100644 --- a/ijkmedia/ijkplayer/ijkplayer.h +++ b/ijkmedia/ijkplayer/ijkplayer.h @@ -150,6 +150,9 @@ struct SDL_Vout; #define IJKMP_OPT_CATEGORY_PLAYER FFP_OPT_CATEGORY_PLAYER #define IJKMP_OPT_CATEGORY_SWR FFP_OPT_CATEGORY_SWR +int ijkmp_start_recording(IjkMediaPlayer *mp, const char *filePath); +int ijkmp_stop_recording(IjkMediaPlayer *mp); +int ijkmp_isRecording(IjkMediaPlayer *mp); void ijkmp_global_init(); void ijkmp_global_uninit(); diff --git a/init-ios.sh b/init-ios.sh index 41a25dc1a5..6752c354f0 100755 --- a/init-ios.sh +++ b/init-ios.sh @@ -39,9 +39,9 @@ fi set -e TOOLS=tools -FF_ALL_ARCHS_IOS6_SDK="armv7 armv7s i386" -FF_ALL_ARCHS_IOS7_SDK="armv7 armv7s arm64 i386 x86_64" -FF_ALL_ARCHS_IOS8_SDK="armv7 arm64 i386 x86_64" +#FF_ALL_ARCHS_IOS6_SDK="armv7 armv7s i386" +#FF_ALL_ARCHS_IOS7_SDK="armv7 armv7s arm64 i386 x86_64" +FF_ALL_ARCHS_IOS8_SDK="arm64 i386 x86_64" FF_ALL_ARCHS=$FF_ALL_ARCHS_IOS8_SDK FF_TARGET=$1 diff --git a/ios/IJKMediaPlayer/IJKMediaPlayer.xcodeproj/project.pbxproj b/ios/IJKMediaPlayer/IJKMediaPlayer.xcodeproj/project.pbxproj index 0f023aecb6..5eb9277f5d 100644 --- a/ios/IJKMediaPlayer/IJKMediaPlayer.xcodeproj/project.pbxproj +++ b/ios/IJKMediaPlayer/IJKMediaPlayer.xcodeproj/project.pbxproj @@ -1102,8 +1102,13 @@ LastUpgradeCheck = 0700; ORGANIZATIONNAME = bilibili; TargetAttributes = { + 5450AFC11E63EA4300568494 = { + DevelopmentTeam = YKSBCJ5G3S; + ProvisioningStyle = Automatic; + }; E654EA891B6B27E600B0F2D0 = { CreatedOnToolsVersion = 6.4; + DevelopmentTeam = YKSBCJ5G3S; }; E654EA931B6B27E600B0F2D0 = { CreatedOnToolsVersion = 6.4; @@ -1115,6 +1120,7 @@ developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( + English, en, ); mainGroup = E6903EB017EAF6C500CFD954; @@ -1393,10 +1399,13 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 0.8.8; DEBUG_INFORMATION_FORMAT = dwarf; DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = YKSBCJ5G3S; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; @@ -1432,8 +1441,9 @@ "-read_only_relocs", suppress, ); - PRODUCT_BUNDLE_IDENTIFIER = "tv.danmaku.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_BUNDLE_IDENTIFIER = com.nhathm.IJKMediaFrameworkWithSSL; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; SKIP_INSTALL = YES; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; @@ -1448,9 +1458,12 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 0.8.8; DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = YKSBCJ5G3S; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; @@ -1483,8 +1496,9 @@ "-read_only_relocs", suppress, ); - PRODUCT_BUNDLE_IDENTIFIER = "tv.danmaku.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_BUNDLE_IDENTIFIER = com.nhathm.IJKMediaFrameworkWithSSL; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; SKIP_INSTALL = YES; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; @@ -1499,10 +1513,12 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CURRENT_PROJECT_VERSION = 0.8.8; DEBUG_INFORMATION_FORMAT = dwarf; DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = YKSBCJ5G3S; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; @@ -1533,10 +1549,11 @@ ); MACH_O_TYPE = staticlib; MTL_ENABLE_DEBUG_INFO = YES; - PRODUCT_BUNDLE_IDENTIFIER = "tv.danmaku.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_BUNDLE_IDENTIFIER = com.nhathm.IJKMediaFramework; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; TARGETED_DEVICE_FAMILY = "1,2"; + VALID_ARCHS = "arm64 arm64e"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; @@ -1552,6 +1569,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CURRENT_PROJECT_VERSION = 0.8.8; DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = YKSBCJ5G3S; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; @@ -1579,10 +1597,11 @@ ); MACH_O_TYPE = staticlib; MTL_ENABLE_DEBUG_INFO = NO; - PRODUCT_BUNDLE_IDENTIFIER = "tv.danmaku.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_BUNDLE_IDENTIFIER = com.nhathm.IJKMediaFramework; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; TARGETED_DEVICE_FAMILY = "1,2"; + VALID_ARCHS = "arm64 arm64e"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; @@ -1683,7 +1702,7 @@ GCC_WARN_SHADOW = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 7.0; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; STRIP_INSTALLED_PRODUCT = NO; @@ -1714,7 +1733,7 @@ GCC_WARN_SHADOW = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 7.0; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; SDKROOT = iphoneos; STRIP_INSTALLED_PRODUCT = NO; VALIDATE_PRODUCT = YES; diff --git a/ios/IJKMediaPlayer/IJKMediaPlayer/IJKFFMoviePlayerController.m b/ios/IJKMediaPlayer/IJKMediaPlayer/IJKFFMoviePlayerController.m index 5263daae27..2e32840b00 100644 --- a/ios/IJKMediaPlayer/IJKMediaPlayer/IJKFFMoviePlayerController.m +++ b/ios/IJKMediaPlayer/IJKMediaPlayer/IJKFFMoviePlayerController.m @@ -450,6 +450,19 @@ - (BOOL)isPlaying return ijkmp_is_playing(_mediaPlayer); } +- (void)stopRecord { + ijkmp_stop_recording(_mediaPlayer); +} + +- (void)startRecordWithFileName:(NSString *)fileName { + const char *path = [fileName cStringUsingEncoding:NSUTF8StringEncoding]; + ijkmp_start_recording(_mediaPlayer, path); +} + +- (BOOL)isRecording { + return ijkmp_isRecording(_mediaPlayer); +} + - (void)setPauseInBackground:(BOOL)pause { _pauseInBackground = pause; diff --git a/ios/IJKMediaPlayer/IJKMediaPlayer/IJKMediaPlayback.h b/ios/IJKMediaPlayer/IJKMediaPlayer/IJKMediaPlayback.h index b5e50e07d6..067addfb6e 100644 --- a/ios/IJKMediaPlayer/IJKMediaPlayer/IJKMediaPlayback.h +++ b/ios/IJKMediaPlayer/IJKMediaPlayer/IJKMediaPlayback.h @@ -102,6 +102,9 @@ typedef NS_ENUM(NSInteger, IJKMPMovieTimeOption) { @property (nonatomic) float playbackVolume; - (UIImage *)thumbnailImageAtCurrentTime; +- (void)stopRecord; +- (void)startRecordWithFileName:(NSString *)fileName; +- (BOOL)isRecording; #pragma mark Notifications