From 487bfc2392f74f19115ab24c129f3513afb2db1a Mon Sep 17 00:00:00 2001 From: NhatHM Date: Tue, 2 Jul 2019 17:16:20 +0700 Subject: [PATCH 1/3] Add record func --- init-ios.sh | 6 +- .../IJKFFMoviePlayerController.m | 255 ++++++++++++++++++ .../IJKMediaPlayer/IJKMediaPlayback.h | 11 + 3 files changed, 269 insertions(+), 3 deletions(-) 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/IJKFFMoviePlayerController.m b/ios/IJKMediaPlayer/IJKMediaPlayer/IJKFFMoviePlayerController.m index 5263daae27..a622e8f91a 100644 --- a/ios/IJKMediaPlayer/IJKMediaPlayer/IJKFFMoviePlayerController.m +++ b/ios/IJKMediaPlayer/IJKMediaPlayer/IJKFFMoviePlayerController.m @@ -761,6 +761,261 @@ - (UIImage *)thumbnailImageAtCurrentTime return nil; } +#pragma --mark 录制视频(只能录制RTSP流)格式mov +- (int)rtsp2mov:(NSString *)streamURL storageFilePath:(NSString *)filePath isStop:(BOOL)bStop +{ + // 输入 + AVStream *i_video_stream = NULL; //视频 + AVStream *i_audio_stream = NULL; //音频 + AVFormatContext *i_fmt_ctx = NULL; + + // 输出 + AVStream *o_video_stream = NULL; //视频 + AVStream *o_audio_stream = NULL; //音频 + AVFormatContext *o_fmt_ctx = NULL; + + // ijkmp_global_init(); + // // FFMPEG注册 + // ijkav_register_all(); + // avcodec_register_all(); + // av_register_all(); + // if(avformat_network_init() != 0){ + // printf("avformat_network_init() 失败 \n"); + // return -1; + // } + + // 视频存储的路径 + const char *filename = [filePath cStringUsingEncoding:NSUTF8StringEncoding]; + // 打开网络流或文件流 + if (avformat_open_input(&i_fmt_ctx, [streamURL cStringUsingEncoding:NSUTF8StringEncoding], NULL, NULL)!=0) + { + printf("无法打开输入流.\n"); + return -1; + } + + if (avformat_find_stream_info(i_fmt_ctx, NULL)<0) + { + printf("找不到流信息.\n"); + return -1; + } + + // 列出输入文件的相关流信息 + printf("---------------- 输入文件信息 ---------------\n"); + av_dump_format(i_fmt_ctx, 0, [streamURL cStringUsingEncoding:NSUTF8StringEncoding], 0); + printf("-------------------------------------------------\n"); + + + /* find first video stream */ + for (unsigned i=0; inb_streams; i++) + { + if (i_fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { + // 视频 + i_video_stream = i_fmt_ctx->streams[i]; + } + else if(i_fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO){ + // 音频 + i_audio_stream = i_fmt_ctx->streams[i]; + } + } + + if (i_video_stream == NULL) + { + fprintf(stderr, "没有找到任何视频流媒体\n"); + return -1; + } + + AVOutputFormat *oformat = av_guess_format(NULL, filename, NULL); + /** + * avformat_alloc_output_context2(AVFormatContext **ctx, AVOutputFormat *oformat, const char *format_name, const char *filename) + * + * ctx: 函数调用成功之后创建的AVFormatContext结构体 + * oformat: 指定AVFormatContext中的AVOutputFormat,用于确定输出格式。如果指定为NULL,可以设定后两个参数(format_name或者filename)由FFmpeg猜测输出格式 + * format_name: 指定输出格式的名称。根据格式名称,FFmpeg会推测输出格式。输出格式可以是“flv”,“mkv”等等 + * filename: 指定输出文件的名称 + */ + if(avformat_alloc_output_context2(&o_fmt_ctx, oformat, NULL, filename) !=0){ + fprintf(stderr, "初始化o_fmt_ctx结构体失败\n"); + return -1; + } + + /**************************************** 视频 **********************************/ + o_video_stream = avformat_new_stream(o_fmt_ctx, NULL); + { + if (o_video_stream == NULL){ + printf("没有获取到视频流信息.\n"); + return -1; + } + + AVCodecParameters *oVcc; + oVcc = o_video_stream->codecpar; + + //平均比特率 + oVcc->bit_rate = 400000; + oVcc->codec_id = i_video_stream->codecpar->codec_id; + oVcc->codec_type = i_video_stream->codecpar->codec_type; + + oVcc->sample_aspect_ratio.num = i_video_stream->sample_aspect_ratio.num; + oVcc->sample_aspect_ratio.den = i_video_stream->sample_aspect_ratio.den; + + oVcc->extradata = i_video_stream->codecpar->extradata; + oVcc->extradata_size = i_video_stream->codecpar->extradata_size; + + oVcc->width = i_video_stream->codecpar->width; + oVcc->height = i_video_stream->codecpar->height; + oVcc->format = i_video_stream->codecpar->format; + + //帧率 + o_video_stream->r_frame_rate = i_video_stream->r_frame_rate; + } + + // oVcc->flags = i_video_stream->codec->flags; + // oVcc->flags |= CODEC_FLAG_GLOBAL_HEADER; + // oVcc->me_range = i_video_stream->codec->me_range; + // oVcc->max_qdiff = i_video_stream->codec->max_qdiff; + // // 最小量化器 + // oVcc->qmin = i_video_stream->codec->qmin; + // // 最大量化器 + // oVcc->qmax = i_video_stream->codec->qmax; + // + // // encoding parameters + // oVcc->qcompress = i_video_stream->codec->qcompress; + + + /**************************************** 音频 **********************************/ + o_audio_stream = avformat_new_stream(o_fmt_ctx, NULL); + { + if (o_audio_stream == NULL){ + printf("没有获取到音频流信息.\n"); + return -1; + } + + AVCodecParameters *oAcc; + oAcc = o_audio_stream->codecpar; + + oAcc->codec_id = AV_CODEC_ID_AAC; //AAC格式 + oAcc->codec_type = AVMEDIA_TYPE_AUDIO; + oAcc->bit_rate = 64000; + //采样率(音频) + oAcc->sample_rate = 44100; + //声道数(音频) + oAcc->channel_layout = AV_CH_LAYOUT_STEREO; + oAcc->channels = av_get_channel_layout_nb_channels(oAcc->channel_layout); + } + + /*******************************************************************************/ + + // 列出输出文件的相关流信息 + printf("------------------- 输出文件信息 ------------------\n"); + av_dump_format(o_fmt_ctx, 0, filename, 1); + printf("-------------------------------------------------\n"); + + avio_open(&o_fmt_ctx->pb, filename, AVIO_FLAG_WRITE); + + + if (!(o_fmt_ctx->flags & AVFMT_NOFILE)) { + + } + + if (!o_fmt_ctx->nb_streams) { + fprintf(stderr, "output file dose not contain any stream\n"); + return -1; + } + + // 根据文件名的后缀写相应格式的文件头 + if (avformat_write_header(o_fmt_ctx, NULL) < 0) { + fprintf(stderr, "Could not write header for output file\n"); + return -1; + } + + int last_pts = 0, last_dts = 0; + int au_pts = 0, au_dts = 0; + + int64_t pts = 0, dts = 0; + int64_t a_pts = 0, a_dts = 0; + + int64_t end_time = 0; + + while (!bStop) + { + end_time++; + AVPacket i_pkt; + av_init_packet(&i_pkt); + i_pkt.size = 0; + i_pkt.data = NULL; + + // 获取流中每一帧的数据流(包) + if (av_read_frame(i_fmt_ctx, &i_pkt) < 0 ) + break; + /* + * pts and dts should increase monotonically + * pts should be >= dts + */ + + if (i_pkt.stream_index == AVMEDIA_TYPE_VIDEO) + { + i_pkt.flags |= AV_PKT_FLAG_KEY; + pts = i_pkt.pts; + i_pkt.pts += last_pts; + dts = i_pkt.dts; + i_pkt.dts += last_dts; + i_pkt.stream_index = 0; + + printf("%lld %lld\n", i_pkt.pts, i_pkt.dts); + + static int num = 1; + printf("frame %d\n", num++); + + // 往输出流中写一个分包 + av_interleaved_write_frame(o_fmt_ctx, &i_pkt); + } + else if (i_pkt.stream_index == AVMEDIA_TYPE_AUDIO){ + i_pkt.flags |= AV_PKT_FLAG_KEY; + a_pts = i_pkt.pts; + i_pkt.pts += au_pts; + a_dts = i_pkt.dts; + i_pkt.dts += au_dts; + i_pkt.stream_index = 1; + + printf("%lld %lld\n", i_pkt.pts, i_pkt.dts); + + static int num = 1; + printf("frame %d\n", num++); + + // 往输出流中写一个分包 + av_interleaved_write_frame(o_fmt_ctx, &i_pkt); + } + + if (end_time == 2000) + { + bStop = YES; + } + } + + last_dts += dts; + last_pts += pts; + + au_dts += a_dts; + au_pts += a_pts; + + avformat_close_input(&i_fmt_ctx); + + // 写输出流(文件)的文件尾 + av_write_trailer(o_fmt_ctx); + + // 视频信息 + av_freep(&o_fmt_ctx->streams[0]->codecpar); + av_freep(&o_fmt_ctx->streams[0]); + + // 音频信息 + av_freep(&o_fmt_ctx->streams[1]->codecpar); + av_freep(&o_fmt_ctx->streams[1]); + + avio_close(o_fmt_ctx->pb); + av_free(o_fmt_ctx); + + return 0; +} + - (CGFloat)fpsAtOutput { return _glView.fps; diff --git a/ios/IJKMediaPlayer/IJKMediaPlayer/IJKMediaPlayback.h b/ios/IJKMediaPlayer/IJKMediaPlayer/IJKMediaPlayback.h index b5e50e07d6..2a161aa05c 100644 --- a/ios/IJKMediaPlayer/IJKMediaPlayer/IJKMediaPlayback.h +++ b/ios/IJKMediaPlayer/IJKMediaPlayer/IJKMediaPlayback.h @@ -103,6 +103,17 @@ typedef NS_ENUM(NSInteger, IJKMPMovieTimeOption) { - (UIImage *)thumbnailImageAtCurrentTime; +// 录制视频(只能录制RTSP流)格式mov +/** + * 录制视频(只能录制RTSP流)格式mov + * + * @param streamURL 流地址 + * @param filePath 录制的视频存储的路径 + * @param bStop 是否开始录制(NO开始, YES结束) + * @return int 返回-1,录制失败, 0为正常 + */ +- (int)rtsp2mov:(NSString *)streamURL storageFilePath:(NSString *)filePath isStop:(BOOL)bStop; + #pragma mark Notifications #ifdef __cplusplus From 929bc10ccb9517d72e78527f7131d2567475ba14 Mon Sep 17 00:00:00 2001 From: NhatHM Date: Thu, 18 Jul 2019 15:29:15 +0700 Subject: [PATCH 2/3] Upgrade OpenGL ES2 to OpenGL ES3 --- ijkmedia/ijksdl/gles2/renderer_rgb.c | 6 +++--- ijkmedia/ijksdl/gles2/renderer_yuv420sp.c | 8 ++++---- ijkmedia/ijksdl/gles2/renderer_yuv420sp_vtb.m | 8 ++++---- ijkmedia/ijksdl/ijksdl_gles2.h | 4 ++-- .../IJKMediaPlayer/ijkmedia/ijksdl/ios/IJKSDLGLView.m | 2 +- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/ijkmedia/ijksdl/gles2/renderer_rgb.c b/ijkmedia/ijksdl/gles2/renderer_rgb.c index bd42f17f54..0a2cbf606a 100644 --- a/ijkmedia/ijksdl/gles2/renderer_rgb.c +++ b/ijkmedia/ijksdl/gles2/renderer_rgb.c @@ -79,7 +79,7 @@ static GLboolean rgb565_uploadTexture(IJK_GLES2_Renderer *renderer, SDL_VoutOver glTexImage2D(GL_TEXTURE_2D, 0, - GL_RGB, + GL_RGB16F, widths[plane], heights[plane], 0, @@ -145,7 +145,7 @@ static GLboolean rgb888_uploadTexture(IJK_GLES2_Renderer *renderer, SDL_VoutOver glTexImage2D(GL_TEXTURE_2D, 0, - GL_RGB, + GL_RGB16F, widths[plane], heights[plane], 0, @@ -211,7 +211,7 @@ static GLboolean rgbx8888_uploadTexture(IJK_GLES2_Renderer *renderer, SDL_VoutOv glTexImage2D(GL_TEXTURE_2D, 0, - GL_RGBA, + GL_RGBA16F, widths[plane], heights[plane], 0, diff --git a/ijkmedia/ijksdl/gles2/renderer_yuv420sp.c b/ijkmedia/ijksdl/gles2/renderer_yuv420sp.c index f90b9b0c73..ae93cb990f 100644 --- a/ijkmedia/ijksdl/gles2/renderer_yuv420sp.c +++ b/ijkmedia/ijksdl/gles2/renderer_yuv420sp.c @@ -80,22 +80,22 @@ static GLboolean yuv420sp_uploadTexture(IJK_GLES2_Renderer *renderer, SDL_VoutOv glBindTexture(GL_TEXTURE_2D, renderer->plane_textures[0]); glTexImage2D(GL_TEXTURE_2D, 0, - GL_RED_EXT, + GL_LUMINANCE, widths[0], heights[0], 0, - GL_RED_EXT, + GL_LUMINANCE, GL_UNSIGNED_BYTE, pixels[0]); glBindTexture(GL_TEXTURE_2D, renderer->plane_textures[1]); glTexImage2D(GL_TEXTURE_2D, 0, - GL_RG_EXT, + GL_LUMINANCE_ALPHA, widths[1], heights[1], 0, - GL_RG_EXT, + GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, pixels[1]); diff --git a/ijkmedia/ijksdl/gles2/renderer_yuv420sp_vtb.m b/ijkmedia/ijksdl/gles2/renderer_yuv420sp_vtb.m index 62c34a3118..6502ebbabb 100644 --- a/ijkmedia/ijksdl/gles2/renderer_yuv420sp_vtb.m +++ b/ijkmedia/ijksdl/gles2/renderer_yuv420sp_vtb.m @@ -138,10 +138,10 @@ static GLboolean yuv420sp_vtb_uploadTexture(IJK_GLES2_Renderer *renderer, SDL_Vo pixel_buffer, NULL, GL_TEXTURE_2D, - GL_RED_EXT, + GL_LUMINANCE, (GLsizei)frame_width, (GLsizei)frame_height, - GL_RED_EXT, + GL_LUMINANCE, GL_UNSIGNED_BYTE, 0, &opaque->cv_texture[0]); @@ -158,10 +158,10 @@ static GLboolean yuv420sp_vtb_uploadTexture(IJK_GLES2_Renderer *renderer, SDL_Vo pixel_buffer, NULL, GL_TEXTURE_2D, - GL_RG_EXT, + GL_LUMINANCE_ALPHA, (GLsizei)frame_width / 2, (GLsizei)frame_height / 2, - GL_RG_EXT, + GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, 1, &opaque->cv_texture[1]); diff --git a/ijkmedia/ijksdl/ijksdl_gles2.h b/ijkmedia/ijksdl/ijksdl_gles2.h index 7c1fdd51c9..5699551fac 100644 --- a/ijkmedia/ijksdl/ijksdl_gles2.h +++ b/ijkmedia/ijksdl/ijksdl_gles2.h @@ -23,8 +23,8 @@ #define IJKSDL__IJKSDL_GLES2_H #ifdef __APPLE__ -#include -#include +#include +#include #else #include #include diff --git a/ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/IJKSDLGLView.m b/ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/IJKSDLGLView.m index 2d7c66515e..c88fc13a71 100644 --- a/ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/IJKSDLGLView.m +++ b/ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/IJKSDLGLView.m @@ -163,7 +163,7 @@ - (BOOL)setupGL [eaglLayer setContentsScale:_scaleFactor]; - _context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; + _context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3]; if (_context == nil) { NSLog(@"failed to setup EAGLContext\n"); return NO; From 5c7884d5139a1f675e0b17ca514392e552c171c1 Mon Sep 17 00:00:00 2001 From: NhatHM Date: Thu, 18 Jul 2019 15:34:28 +0700 Subject: [PATCH 3/3] Remove unneeded change --- .../IJKFFMoviePlayerController.m | 255 ------------------ .../IJKMediaPlayer/IJKMediaPlayback.h | 11 - 2 files changed, 266 deletions(-) diff --git a/ios/IJKMediaPlayer/IJKMediaPlayer/IJKFFMoviePlayerController.m b/ios/IJKMediaPlayer/IJKMediaPlayer/IJKFFMoviePlayerController.m index a622e8f91a..5263daae27 100644 --- a/ios/IJKMediaPlayer/IJKMediaPlayer/IJKFFMoviePlayerController.m +++ b/ios/IJKMediaPlayer/IJKMediaPlayer/IJKFFMoviePlayerController.m @@ -761,261 +761,6 @@ - (UIImage *)thumbnailImageAtCurrentTime return nil; } -#pragma --mark 录制视频(只能录制RTSP流)格式mov -- (int)rtsp2mov:(NSString *)streamURL storageFilePath:(NSString *)filePath isStop:(BOOL)bStop -{ - // 输入 - AVStream *i_video_stream = NULL; //视频 - AVStream *i_audio_stream = NULL; //音频 - AVFormatContext *i_fmt_ctx = NULL; - - // 输出 - AVStream *o_video_stream = NULL; //视频 - AVStream *o_audio_stream = NULL; //音频 - AVFormatContext *o_fmt_ctx = NULL; - - // ijkmp_global_init(); - // // FFMPEG注册 - // ijkav_register_all(); - // avcodec_register_all(); - // av_register_all(); - // if(avformat_network_init() != 0){ - // printf("avformat_network_init() 失败 \n"); - // return -1; - // } - - // 视频存储的路径 - const char *filename = [filePath cStringUsingEncoding:NSUTF8StringEncoding]; - // 打开网络流或文件流 - if (avformat_open_input(&i_fmt_ctx, [streamURL cStringUsingEncoding:NSUTF8StringEncoding], NULL, NULL)!=0) - { - printf("无法打开输入流.\n"); - return -1; - } - - if (avformat_find_stream_info(i_fmt_ctx, NULL)<0) - { - printf("找不到流信息.\n"); - return -1; - } - - // 列出输入文件的相关流信息 - printf("---------------- 输入文件信息 ---------------\n"); - av_dump_format(i_fmt_ctx, 0, [streamURL cStringUsingEncoding:NSUTF8StringEncoding], 0); - printf("-------------------------------------------------\n"); - - - /* find first video stream */ - for (unsigned i=0; inb_streams; i++) - { - if (i_fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { - // 视频 - i_video_stream = i_fmt_ctx->streams[i]; - } - else if(i_fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO){ - // 音频 - i_audio_stream = i_fmt_ctx->streams[i]; - } - } - - if (i_video_stream == NULL) - { - fprintf(stderr, "没有找到任何视频流媒体\n"); - return -1; - } - - AVOutputFormat *oformat = av_guess_format(NULL, filename, NULL); - /** - * avformat_alloc_output_context2(AVFormatContext **ctx, AVOutputFormat *oformat, const char *format_name, const char *filename) - * - * ctx: 函数调用成功之后创建的AVFormatContext结构体 - * oformat: 指定AVFormatContext中的AVOutputFormat,用于确定输出格式。如果指定为NULL,可以设定后两个参数(format_name或者filename)由FFmpeg猜测输出格式 - * format_name: 指定输出格式的名称。根据格式名称,FFmpeg会推测输出格式。输出格式可以是“flv”,“mkv”等等 - * filename: 指定输出文件的名称 - */ - if(avformat_alloc_output_context2(&o_fmt_ctx, oformat, NULL, filename) !=0){ - fprintf(stderr, "初始化o_fmt_ctx结构体失败\n"); - return -1; - } - - /**************************************** 视频 **********************************/ - o_video_stream = avformat_new_stream(o_fmt_ctx, NULL); - { - if (o_video_stream == NULL){ - printf("没有获取到视频流信息.\n"); - return -1; - } - - AVCodecParameters *oVcc; - oVcc = o_video_stream->codecpar; - - //平均比特率 - oVcc->bit_rate = 400000; - oVcc->codec_id = i_video_stream->codecpar->codec_id; - oVcc->codec_type = i_video_stream->codecpar->codec_type; - - oVcc->sample_aspect_ratio.num = i_video_stream->sample_aspect_ratio.num; - oVcc->sample_aspect_ratio.den = i_video_stream->sample_aspect_ratio.den; - - oVcc->extradata = i_video_stream->codecpar->extradata; - oVcc->extradata_size = i_video_stream->codecpar->extradata_size; - - oVcc->width = i_video_stream->codecpar->width; - oVcc->height = i_video_stream->codecpar->height; - oVcc->format = i_video_stream->codecpar->format; - - //帧率 - o_video_stream->r_frame_rate = i_video_stream->r_frame_rate; - } - - // oVcc->flags = i_video_stream->codec->flags; - // oVcc->flags |= CODEC_FLAG_GLOBAL_HEADER; - // oVcc->me_range = i_video_stream->codec->me_range; - // oVcc->max_qdiff = i_video_stream->codec->max_qdiff; - // // 最小量化器 - // oVcc->qmin = i_video_stream->codec->qmin; - // // 最大量化器 - // oVcc->qmax = i_video_stream->codec->qmax; - // - // // encoding parameters - // oVcc->qcompress = i_video_stream->codec->qcompress; - - - /**************************************** 音频 **********************************/ - o_audio_stream = avformat_new_stream(o_fmt_ctx, NULL); - { - if (o_audio_stream == NULL){ - printf("没有获取到音频流信息.\n"); - return -1; - } - - AVCodecParameters *oAcc; - oAcc = o_audio_stream->codecpar; - - oAcc->codec_id = AV_CODEC_ID_AAC; //AAC格式 - oAcc->codec_type = AVMEDIA_TYPE_AUDIO; - oAcc->bit_rate = 64000; - //采样率(音频) - oAcc->sample_rate = 44100; - //声道数(音频) - oAcc->channel_layout = AV_CH_LAYOUT_STEREO; - oAcc->channels = av_get_channel_layout_nb_channels(oAcc->channel_layout); - } - - /*******************************************************************************/ - - // 列出输出文件的相关流信息 - printf("------------------- 输出文件信息 ------------------\n"); - av_dump_format(o_fmt_ctx, 0, filename, 1); - printf("-------------------------------------------------\n"); - - avio_open(&o_fmt_ctx->pb, filename, AVIO_FLAG_WRITE); - - - if (!(o_fmt_ctx->flags & AVFMT_NOFILE)) { - - } - - if (!o_fmt_ctx->nb_streams) { - fprintf(stderr, "output file dose not contain any stream\n"); - return -1; - } - - // 根据文件名的后缀写相应格式的文件头 - if (avformat_write_header(o_fmt_ctx, NULL) < 0) { - fprintf(stderr, "Could not write header for output file\n"); - return -1; - } - - int last_pts = 0, last_dts = 0; - int au_pts = 0, au_dts = 0; - - int64_t pts = 0, dts = 0; - int64_t a_pts = 0, a_dts = 0; - - int64_t end_time = 0; - - while (!bStop) - { - end_time++; - AVPacket i_pkt; - av_init_packet(&i_pkt); - i_pkt.size = 0; - i_pkt.data = NULL; - - // 获取流中每一帧的数据流(包) - if (av_read_frame(i_fmt_ctx, &i_pkt) < 0 ) - break; - /* - * pts and dts should increase monotonically - * pts should be >= dts - */ - - if (i_pkt.stream_index == AVMEDIA_TYPE_VIDEO) - { - i_pkt.flags |= AV_PKT_FLAG_KEY; - pts = i_pkt.pts; - i_pkt.pts += last_pts; - dts = i_pkt.dts; - i_pkt.dts += last_dts; - i_pkt.stream_index = 0; - - printf("%lld %lld\n", i_pkt.pts, i_pkt.dts); - - static int num = 1; - printf("frame %d\n", num++); - - // 往输出流中写一个分包 - av_interleaved_write_frame(o_fmt_ctx, &i_pkt); - } - else if (i_pkt.stream_index == AVMEDIA_TYPE_AUDIO){ - i_pkt.flags |= AV_PKT_FLAG_KEY; - a_pts = i_pkt.pts; - i_pkt.pts += au_pts; - a_dts = i_pkt.dts; - i_pkt.dts += au_dts; - i_pkt.stream_index = 1; - - printf("%lld %lld\n", i_pkt.pts, i_pkt.dts); - - static int num = 1; - printf("frame %d\n", num++); - - // 往输出流中写一个分包 - av_interleaved_write_frame(o_fmt_ctx, &i_pkt); - } - - if (end_time == 2000) - { - bStop = YES; - } - } - - last_dts += dts; - last_pts += pts; - - au_dts += a_dts; - au_pts += a_pts; - - avformat_close_input(&i_fmt_ctx); - - // 写输出流(文件)的文件尾 - av_write_trailer(o_fmt_ctx); - - // 视频信息 - av_freep(&o_fmt_ctx->streams[0]->codecpar); - av_freep(&o_fmt_ctx->streams[0]); - - // 音频信息 - av_freep(&o_fmt_ctx->streams[1]->codecpar); - av_freep(&o_fmt_ctx->streams[1]); - - avio_close(o_fmt_ctx->pb); - av_free(o_fmt_ctx); - - return 0; -} - - (CGFloat)fpsAtOutput { return _glView.fps; diff --git a/ios/IJKMediaPlayer/IJKMediaPlayer/IJKMediaPlayback.h b/ios/IJKMediaPlayer/IJKMediaPlayer/IJKMediaPlayback.h index 2a161aa05c..b5e50e07d6 100644 --- a/ios/IJKMediaPlayer/IJKMediaPlayer/IJKMediaPlayback.h +++ b/ios/IJKMediaPlayer/IJKMediaPlayer/IJKMediaPlayback.h @@ -103,17 +103,6 @@ typedef NS_ENUM(NSInteger, IJKMPMovieTimeOption) { - (UIImage *)thumbnailImageAtCurrentTime; -// 录制视频(只能录制RTSP流)格式mov -/** - * 录制视频(只能录制RTSP流)格式mov - * - * @param streamURL 流地址 - * @param filePath 录制的视频存储的路径 - * @param bStop 是否开始录制(NO开始, YES结束) - * @return int 返回-1,录制失败, 0为正常 - */ -- (int)rtsp2mov:(NSString *)streamURL storageFilePath:(NSString *)filePath isStop:(BOOL)bStop; - #pragma mark Notifications #ifdef __cplusplus