美文网首页音视频积累
FFmpeg学习笔记(三)

FFmpeg学习笔记(三)

作者: Hunter琼 | 来源:发表于2021-03-27 13:23 被阅读0次

    接着上文继续开车,https://www.jianshu.com/p/6e3163a6805b,体会vi打码的酸爽!!!

    6视频的裁剪

    #include <libavformat/avformat.h>
    #include <libavutil/log.h>
    #include <libavutil/timestamp.h>
    #include <stdlib.h>
    //implicit declaration of function 'atio'
    
    static void log_packet(const AVFormatContext *fmt_ctx, const AVPacket *pkt, const char *tag)
    {
        AVRational *time_base = &fmt_ctx->streams[pkt->stream_index]->time_base;
    
        printf("%s: pts:%s pts_time:%s dts:%s dts_time:%s duration:%s duration_time:%s stream_index:%d\n",
               tag,
               av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, time_base),
               av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, time_base),
               av_ts2str(pkt->duration), av_ts2timestr(pkt->duration, time_base),
               pkt->stream_index);
    }
    
    
    
    int tailoring_Video(double from_seconds,double end_seconds,const char *in_filename,const char *out_filename){
    
       AVFormatContext *ifmt_ctx = NULL, *ofmt_ctx = NULL;
    
       AVOutputFormat *ofmt = NULL;
      
       AVPacket pkt;
    
       int ret,i;
    
        #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 9, 100)
        av_register_all();
         #endif
        #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 10, 100)
          avcodec_register_all();
        #endif
    
        ret = avformat_open_input(&ifmt_ctx,in_filename,0,0);
    
        if(ret < 0){
          av_log(NULL,AV_LOG_ERROR,"不能打开%s\n",in_filename);
    
          goto fail;
     
        }
        
        ret = avformat_find_stream_info(ifmt_ctx,0);
    
        if(ret < 0){
         
         av_log(NULL,AV_LOG_ERROR,"没有发现输入文件流\n");
    
         goto fail;
    
        }
        
        av_dump_format(ifmt_ctx,0,in_filename,0);
        // 输出文件上下文
        avformat_alloc_output_context2(&ofmt_ctx,NULL,NULL,out_filename);
         
        if(!ofmt_ctx){
    
        av_log(NULL,AV_LOG_ERROR,"输出音频文件上下文创建失败\n");
        
        ret = AVERROR_UNKNOWN;
    
        goto fail;
    
        }
        
        ofmt = ofmt_ctx ->oformat;
    
        for(int i = 0; i < ifmt_ctx->nb_streams;i++){
         //拷贝流
         // // 在内存中拷贝一份多媒体文件
          AVStream *in_stream = ifmt_ctx ->streams[i];
          AVStream *out_stream = avformat_new_stream(ofmt_ctx,in_stream->codec->codec);
          if(!out_stream){
    
           av_log(NULL,AV_LOG_ERROR,"错误的输出流信息\n");
           ret = AVERROR_UNKNOWN;
           goto fail;
          }
          // 拷贝codec
          ret = avcodec_copy_context(out_stream->codec,in_stream->codec);
    
          if(ret < 0){
            av_log(NULL,AV_LOG_ERROR,"音视频流上下文拷贝失败\n ");
          ret = AVERROR_UNKNOWN;
           goto fail;
          }
    
          out_stream->codec->codec_tag = 0;
    
          if(ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER){
            out_stream->codec->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
          }
    
        }
    
        av_dump_format(ofmt_ctx,0,out_filename,1);
        
        if(!(ofmt->flags & AVFMT_NOFILE)){
          
          ret = avio_open(&ofmt_ctx->pb,out_filename,AVIO_FLAG_WRITE);
    
          if(ret < 0){
             av_log(NULL,AV_LOG_ERROR,"打开输出文件%s失败\n",out_filename);
         goto fail;
    
          }
        }
        
        // 多媒体头
        ret  = avformat_write_header(ofmt_ctx,NULL);
    
        if(ret < 0){
           av_log(NULL,AV_LOG_ERROR,"打开输出文件发生错误%s\n",av_err2str(ret));
           goto fail;
        }
        
        // 截取一段时间,相当于拖一段时间
        ret = av_seek_frame(ifmt_ctx,-1,from_seconds * AV_TIME_BASE,AVSEEK_FLAG_ANY);
    
        if(ret < 0){
          av_log(NULL,AV_LOG_ERROR,"错误seek\n");
          goto fail;
        }
        
        
        int64_t *dstStartFrom = malloc(sizeof(int64_t) * ifmt_ctx ->nb_streams);
        //向内存区域填充特定的值
        memset(dstStartFrom,0,sizeof(int64_t)*ifmt_ctx->nb_streams);
    
        int64_t *ptsStartFrom = malloc(sizeof(int64_t) *ifmt_ctx->nb_streams);
        
        memset(ptsStartFrom,0,sizeof(int64_t) * ifmt_ctx->nb_streams);
    
        while(1){
    
          AVStream *in_stream,*out_stream;
          // 读取的是压缩包
          ret = av_read_frame(ifmt_ctx,&pkt);
    
          if(ret < 0)break;
    
          in_stream = ifmt_ctx->streams[pkt.stream_index];
          out_stream = ofmt_ctx->streams[pkt.stream_index];
    
          log_packet(ifmt_ctx,&pkt,"in");
          // 时间戳的比较 超过结尾时间 就跳槽循环
          if(av_q2d(in_stream->time_base) * pkt.pts > end_seconds){
    
           av_free_packet(&pkt);
    
           break;
          }
          if(dstStartFrom[pkt.stream_index]== 0){
    
            dstStartFrom[pkt.stream_index] = pkt.dts;
    
           printf("dstStartFrom:%s\n",av_ts2str(dstStartFrom[pkt.stream_index]));
    
          }
    
          if(ptsStartFrom[pkt.stream_index]== 0){
            ptsStartFrom[pkt.stream_index] = pkt.pts;
            
            printf("ptsStartFrom:%s\n",av_ts2str(ptsStartFrom[pkt.stream_index])    );
         
       }
    
       //改变时间基并拷贝包
            
       // [mp4 @ 0x7ff8f7008200] pts (14448) < dts (18060) in stream 0
    
       pkt.pts = av_rescale_q_rnd(pkt.pts - ptsStartFrom[pkt.stream_index],in_stream->time_base,out_stream->time_base,AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
    
       pkt.dts = av_rescale_q_rnd(pkt.dts - dstStartFrom[pkt.stream_index],in_stream->time_base,out_stream->time_base,AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX);
    
       if(pkt.pts < 0){
         pkt.pts = 0;
       }
       
       if(pkt.dts < 0){
    
        pkt.dts = 0;
       }
    
     if(pkt.pts < pkt.dts) continue;
      
       pkt.duration = (int)av_rescale_q((int64_t)pkt.duration,in_stream->time_base,out_stream->time_base);
    
       pkt.pos = -1;
    
       log_packet(ofmt_ctx,&pkt,"out");
    
       ret = av_interleaved_write_frame(ofmt_ctx,&pkt);
    
       if(ret < 0){
         
           av_log(NULL,AV_LOG_ERROR,"错误的包\n");
    
         break;
       }
    
       av_free_packet(&pkt);
    
      }  
      
      free(dstStartFrom);
      free(ptsStartFrom);
    
      av_write_trailer(ofmt_ctx);
    
      fail:
       
       avformat_close_input(&ifmt_ctx);
    
       if(ofmt_ctx && !(ofmt->flags & AVFMT_NOFILE))
    // Segmentation fault: 11
        avio_closep(&ofmt_ctx->pb);
        
        avformat_free_context(ofmt_ctx);
    
       if(ret < 0 && ret != AVERROR_EOF){
        
        av_log(NULL,AV_LOG_ERROR,"发送未知错误:%s",av_err2str(ret));
        return -1;
       }
        
       return 0;
    
    }
    
    
    int main(int argc ,char *argv[]){
      
      av_log_set_level(AV_LOG_INFO);
    
       if(argc < 5){
         av_log(NULL,AV_LOG_ERROR,"缺少参数!!!");
         return -1;
       }
       
       double startTime = atoi(argv[1]);
       double endTime = atoi(argv[2]);
    
       tailoring_Video(startTime,endTime,argv[3],argv[4]);
    
       return 0;
    
    
    
    }
    

    编译可以通过,但有多出警告!!! 运行错误,没有找到问题,欢迎大佬指正!!!


    image.png

    运行结果:


    image.png

    pts (0) < dts (3600) in stream 0错误的包在while(1)循环加if(pkt.pts < pkt.dts) continue;

    播放这个裁剪视频会有一些报错

     illegal short term buffer state detected  [h264 @ 0x7f89100da200] Missing reference picture, default is 0
    [h264 @ 0x7f89100da200] decode_slice_header error
    [h264 @ 0x7f8910054800] Missing reference picture, default is 0
    [h264 @ 0x7f8910054800] decode_slice_header error
    [h264 @ 0x7f8910054e00] reference picture missing during reorder
        Last message repeated 4 times
    [h264 @ 0x7f8910054e00] Missing reference picture, default is 0
    [h264 @ 0x7f8910054e00] decode_slice_header error 
    

    7 iOS实战演练一

    实现功能:有个两个音视频文件,抽取其中一个的音频流和另个一个视频的视频流,进行合并成一个音视频文件,还需要裁减 .
    实际应用就是音视频App小咖秀功能.

    (1)首先编译出iOS可用的的库 可参考 https://www.jianshu.com/p/ec432a8f5729 编译过程中可能出现Failed to connect to raw.githubusercontent.com port 443: Connection refused 在host配置下对应的ip就可以下载了
    对应的ios使用库.png
    (2) OC和C进行混编,实现即可
    image.png

    相关文章

      网友评论

        本文标题:FFmpeg学习笔记(三)

        本文链接:https://www.haomeiwen.com/subject/zhqshltx.html