美文网首页音视频积累
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