ios ffmpeg 保存mp4


废话不说,直接上代码:

header写入成功:

-(void) init_mp4saving:(AVFormatContext*) pFormatCtx videoStreamin:(int) videoStream savenamein:(NSString *)savename {
    
    i_video_stream=pFormatCtx->streams[videoStream];
    int ret;
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSCalendar *curCalendar = [NSCalendar currentCalendar];
    NSUInteger unitFlags = NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit;
    NSDateComponents *dateComponents = [curCalendar components:unitFlags fromDate:[NSDate date]];
    movBasePath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
    filePath = [movBasePath stringByAppendingPathComponent:[NSString stringWithFormat:@"%ld-%ld-%ld.mp4",(long)dateComponents.hour, (long)dateComponents.minute, (long)dateComponents.second ]];
    [fileManager createFileAtPath:filePath contents:nil attributes:nil];
    const char *out_filename = [filePath UTF8String];//URL 路径
    //    av_register_all();//注册所有容器格式和CODEC
    avformat_alloc_output_context2(&outfmt_ctx, NULL, "mp4", out_filename);// 初始化一个用于输出的AVFormatContext结构体
    if (!outfmt_ctx) {
        NSLog(@ "Could not create output context\n");
    }
    outFormat = outfmt_ctx->oformat;
    AVCodec *codec = avcodec_find_decoder(AV_CODEC_ID_H264);//查找对应的解码器
    AVStream *out_stream = avformat_new_stream(outfmt_ctx, codec);//创建输出码流的AVStream
    if (!out_stream){
        NSLog(@ "Failed allocating output stream\n");
    }
    out_Cdc_ctx=out_stream->codec;
    out_Cdc_ctx->pix_fmt = i_video_stream->codec->pix_fmt;
    int FPS=30;
    out_Cdc_ctx = out_stream->codec;
    out_Cdc_ctx->extradata = i_video_stream->codec->extradata;
    out_Cdc_ctx->extradata_size = i_video_stream->codec->extradata_size;
    out_Cdc_ctx->bit_rate = 16*1000;
    out_Cdc_ctx->codec_id = i_video_stream->codec->codec_id;
    out_Cdc_ctx->codec_type = i_video_stream->codec->codec_type;
    out_Cdc_ctx->time_base.num =1;// i_video_stream->time_base.num;
    out_Cdc_ctx->time_base.den =25;// i_video_stream->time_base.den;
    out_Cdc_ctx->time_base = (AVRational){1,FPS};
    fprintf(stderr, "time_base.num = %d time_base.den = %d\n", out_Cdc_ctx->time_base.num, out_Cdc_ctx->time_base.den);
    out_Cdc_ctx->width = i_video_stream->codec->width;
    out_Cdc_ctx->height = i_video_stream->codec->height;
    out_Cdc_ctx->pix_fmt = i_video_stream->codec->pix_fmt;
    NSLog(@"mp4save width:%d height:%d pix_fmt: %d", out_Cdc_ctx->width, out_Cdc_ctx->height, out_Cdc_ctx->pix_fmt);
    out_Cdc_ctx->flags = i_video_stream->codec->flags;
    out_Cdc_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER;
    out_Cdc_ctx->me_range = i_video_stream->codec->me_range;
    out_Cdc_ctx->max_qdiff = i_video_stream->codec->max_qdiff;
    out_Cdc_ctx->qmin = i_video_stream->codec->qmin;
    out_Cdc_ctx->qmax = i_video_stream->codec->qmax;
    out_Cdc_ctx->qcompress = i_video_stream->codec->qcompress;
    //    ret = avcodec_copy_context(out_stream->codec, avcodec_alloc_context3(codec));//拷贝输入视频码流的AVCodecContex的数值t到输出视频的AVCodecContext。
    //    if (ret < 0)
    //    {
    //        NSLog(@ "Failed to copy context from input to output stream codec context\n");
    //    }
    //    out_stream->codec->pix_fmt = AV_PIX_FMT_YUV420P;//支持的像素格式
    //    out_stream->codec->flags = CODEC_FLAG_GLOBAL_HEADER;
    //    out_stream->codec->width = i_video_stream->codec->width;
    //    out_stream->codec->height = i_video_stream->codec->height;
    //    out_stream->time_base=i_video_stream->time_base;
        out_stream->codec->time_base = (AVRational){1,FPS};
        out_stream->codec->gop_size = FPS;
    //    out_stream->codec->bit_rate = 16*1000;
    //    out_stream->codec->codec_tag = 0;
    out_stream->codec->time_base = (AVRational){1,FPS};
    if (outfmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
    {
        out_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
    }
    //    AVBitStreamFilterContext \*avFilter = av_bitstream_filter_init("h264_mp4toannexb");
    //    out_stream->codec->extradata_size = size;
    //    out_stream->codec->extradata = (uint8_t \*)av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE);
    //输出一下格式------------------
    av_dump_format(outfmt_ctx, 0, out_filename, 1);
    if (!(outFormat->flags & AVFMT_NOFILE))
    {
                ret = avio_open(&outfmt_ctx->pb, out_filename, AVIO_FLAG_WRITE);
                if (ret < 0)
                {
                    NSLog(@ "Could not open output file %@", out_filename);
                }
    }
    //    //写文件头(Write file header)
    AVDictionary* opt = NULL;
    //av_dict_set(&opt, "video_track_timescale", "25", 0);
    av_dict_set(&opt, "timescale", "25", 0);
    av_dict_set(&opt, "video_timescale", "25", 0);
    av_dict_set(&opt, "track_timescale", "25", 0);
        ret = avformat_write_header(outfmt_ctx, &opt);
        if (ret < 0)
        {
            NSLog(@ "Error occurred when opening output file\n");
        }
    //    input_video_stream = *(pFormatCtx->streams[videoStream]);
    //o_video_stream->time_base.num = 1;
    // o_video_stream->time_base.den = 25;
   }

保存帧和尾的代码:

  bool isIDR = true;
               unsigned char c[5] ={ 0x00, 0x00, 0x00, 0x01, 0x67};
               int n=0;
               for( n =0 ;n<5;n++){
                   if(vp.data[n]!=c[n]){
                       isIDR=false;break;
                   }
               }
               if(!isIDR){
                   if(record_status==1){
//                       sprintf(savename,"/sdcard/record_%d.mp4", ++record_num);
                        savename = [NSHomeDirectory()stringByAppendingPathComponent:@"Documents/Movie2.mp4"];
                       [self init_mp4saving:pFormatCtx videoStreamin:videoStream savenamein:savename ];
                       last_pts = 0;
                       last_dts = 0;
                       finished = 0;
                       NSLog(@"record_status ok  : record_status = %d \n",record_status);
                       record_status=2;
                   }
               }
               
               if(record_status==2){
                   frame_num++;
                   NSLog(@"record_status ok  : record_status = %d \n",record_status);
                   NSLog(@"frame index %d\n", frame_num);
                   packet.flags |= AV_PKT_FLAG_KEY;
                   packet.pts += last_pts;
//                   if (pCodecCtx->coded_frame->pts != AV_NOPTS_VALUE){
//                       packet.pts= av_rescale_q(pCodecCtx->coded_frame->pts, pCodecCtx->time_base, _videoStream->time_base);
//                       NSLog(@"frame index2 %d packet->pts %d\n", frame_num,packet.pts);
//                   }
                   packet.dts += last_dts;
                   packet.stream_index = 0;
                   packet.duration=1;
                   
                   av_interleaved_write_frame(outfmt_ctx, &packet);
                   if(frame_num>200){
                       record_status=3;
                   }
               }  else if(record_status==3){
                   // avformat_close_input(&i_fmt_ctx);
                   
                   NSLog(@"av_write_trailer!!!!!!!!!!  \n" );
                   av_write_trailer(outfmt_ctx);
                   
                   NSLog(@" avcodec_close!!!!!!!!  \n" );
                   avcodec_close(outfmt_ctx->streams[0]->codec);
                   
                   av_freep(&outfmt_ctx->streams[0]->codec);
                   av_freep(&outfmt_ctx->streams[0]);
                   avio_close(outfmt_ctx->pb);
                   av_free(outfmt_ctx);
                   record_status = 0;
                   NSLog(@"record_end\n");
               }

在使用ffmpeg保存mp4文件时,可以使用以下参数进行配置:-f image2pipe -use_wallclock_as_timestamps 1 -i - -c:v libx264 -pix_fmt yuv420p -vsync passthrough -maxrate 5000k -an -y [2]。其中,-f image2pipe表示从标准输入流中读取图像数据,-use_wallclock_as_timestamps 1表示使用当前系统时间作为时间戳,-i -表示从标准输入流中读取数据,-c:v libx264表示使用libx264编码器进行视频编码,-pix_fmt yuv420p表示使用yuv420p像素格式,-vsync passthrough表示保持输入视频帧的时间戳,-maxrate 5000k表示设置视频的最大码率为5000k,-an表示不包含音频流,-y表示覆盖已存在的输出文件 。这些参数可以满足保存mp4文件的需求。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [【C#】使用ffmpeg image2pipe将图片保存mp4视频](https://blog.csdn.net/catshitone/article/details/126930470)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [FFMPEG录屏保存mp4](https://blog.csdn.net/Donghui_Luo/article/details/88383313)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AI算法网奇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值