【问题标题】:x264 & libavcodecx264 和 libavcodec
【发布时间】:2012-01-17 04:30:31
【问题描述】:

在尝试在 Windows 上使用 x264 编码器构建 ffmpeg 静态库之后,我花了一些时间来编写一些示例。 当然,有很多关于如何构建、如何使用、等等的“说明”……但是,它们都不能在 Windows 上运行。我猜Linux的家伙在这里处于更好的位置。现在,数十亿美元的问题是“这一切的目的是什么?”。这不仅在 Windows 上没用,而且我还可以购买一些真正有效的第三方库。

如果有人要说“但是,它有效!”。我必须说,给我一个工作证明。我不在乎 10fps 的 200x100。我不需要H264。向我展示如何压缩一秒钟的 1080i 素材。它是 H264,它是跨平台的(如果你问我,这听起来很有趣),Google 正在使用它(它必须是完美的,对吗?),这里更时髦......

【问题讨论】:

    标签: windows x264 libavcodec


    【解决方案1】:

    首先不要尝试在 Windows 上构建 - 特别是如果你使用 VS - 从here获取它

    那么序列是这样的:

     // in ctor
     ffmpeg::avcodec_register_all();   
     ffmpeg::avcodec_init();   
     ffmpeg::av_register_all();
    
    bool createFile(const String &fileName,unsigned int width,unsigned int height,unsigned int fps)
    {
    
       close();
    
       pFormatCtx=ffmpeg::avformat_alloc_context();
       if(!pFormatCtx)
       {
          printf("Error allocating format context\n");
          return false;
       }
    
    
        pOutputFormat = ffmpeg::av_guess_format( "mp4", filename,NULL);
    
    
       pFormatCtx->oformat = pOutputFormat;
       _snprintf(pFormatCtx->filename, sizeof(pFormatCtx->filename), "%s",filename);
    
       // Add the video stream
       pVideoStream = av_new_stream(pFormatCtx,0);
       if(!pVideoStream )
       {
          printf("Could not allocate stream\n");
          return false;
       }
    
    
       pCodecCtx=pVideoStream->codec;   
       pCodecCtx->codec_id = pOutputFormat->video_codec;
       pCodecCtx->codec_type = ffmpeg::AVMEDIA_TYPE_VIDEO;
    
    
        pCodecCtx->width = Width = width;
        pCodecCtx->height = Height = height;    
        pCodecCtx->time_base.num = 1;
        pCodecCtx->time_base.den = Fps = fps;   
        pCodecCtx->pix_fmt = ffmpeg::PIX_FMT_YUV420P;
    
    
        // needed for x264 to work
         pCodecCtx->me_range = 16;
         pCodecCtx->max_qdiff = 4;
         pCodecCtx->qmin = 10;
         pCodecCtx->qmax = 51;
         pCodecCtx->qcompress = 0.6;
         pCodecCtx->gop_size = 12;
    
    
    
    
        avcodec_thread_init(pCodecCtx, 10);
    
    
       // some formats want stream headers to be separate
       if(pFormatCtx->oformat->flags & AVFMT_GLOBALHEADER)
          pCodecCtx->flags |= CODEC_FLAG_GLOBAL_HEADER;
    
    
       if (av_set_parameters(pFormatCtx, NULL) < 0)
       {
          printf("Invalid output format parameters\n");
          return false;
       }
    
       ffmpeg::dump_format(pFormatCtx, 0, pFormatCtx->filename, 1);
    
       // open_video
       // find the video encoder
       pCodec = avcodec_find_encoder(pCodecCtx->codec_id);
       if (!pCodec)
       {
          printf("codec not found\n");
          return false;
       }
       // open the codec
       if (avcodec_open(pCodecCtx, pCodec) < 0)
       {
          printf("could not open codec\n");
          return false;
       }
    
       // Allocate memory for output
       if(!initOutputBuf())
       {
          printf("Can't allocate memory for output bitstream\n");
          return false;
       }
    
       // Allocate the YUV frame
       if(!initFrame())
       {
          printf("Can't init frame\n");
          return false;
       }
    
       if (url_fopen(&pFormatCtx->pb,pFormatCtx->filename, URL_WRONLY) < 0)
       {
          printf( "Could not open '%s'\n", pFormatCtx->filename);
          return false;
       }
    
    
        av_write_header(pFormatCtx);
    
       return true;
    }
    

    然后对于每一帧

    int encodeImage(const QImage &img)
    {
    
       if (!convertImage_sws(img)) {     // SWS conversion
           return false;
       }
    
    
       ppicture->pts=pCodecCtx->frame_number;
    
       //memset(outbuf,0,outbuf_size);
       int out_size = ffmpeg::avcodec_encode_video(pCodecCtx,outbuf,outbuf_size,ppicture);
    
       if (out_size > 0)   {
            ffmpeg::AVPacket pkt; 
            av_init_packet(&pkt);
    
    
          if (pCodecCtx->coded_frame->pts != (0x8000000000000000LL))
             pkt.pts= av_rescale_q(pCodecCtx->coded_frame->pts, pCodecCtx->time_base, pVideoStream->time_base);
    
          if(pCodecCtx->coded_frame->key_frame)
             pkt.flags |= AV_PKT_FLAG_KEY;
    
          pkt.stream_index= pVideoStream->index;
          pkt.data= outbuf;
          pkt.size= out_size;      
          if (av_write_frame(pFormatCtx, &pkt) < 0 ) {        
              return 0;
          }           
       }
    
       return out_size;
    }
    
    void close()
    {
    
       av_write_trailer(pFormatCtx);
    
       // close_video
       avcodec_close(pVideoStream->codec);
       freeFrame();
       freeOutputBuf();
    
    
       /* free the streams */
       for(int i = 0; i < pFormatCtx->nb_streams; i++)
       {
          av_freep(&pFormatCtx->streams[i]->codec);
          av_freep(&pFormatCtx->streams[i]);
       }
    
       // Close file
       url_fclose(pFormatCtx->pb);
    
       // Free the stream
       av_free(pFormatCtx);
    
    }
    
    
    bool initFrame()
    {
       ppicture = ffmpeg::avcodec_alloc_frame();
       if(ppicture==0)
          return false;
    
       int size = avpicture_get_size(pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height);
       picture_buf = new uint8_t[size];
       if(picture_buf==0)
       {
          av_free(ppicture);
          ppicture=0;
          return false;
       }
    
       // Setup the planes
       avpicture_fill((ffmpeg::AVPicture *)ppicture, picture_buf,pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height);
    
       ppicture->pts = 0;
       return true;
    }
    

    【讨论】:

    • 在发帖之前我做了几乎同样的事情。但是,我仍然缺少隔行扫描的部分。 x264 如何知道它正在压缩隔行扫描帧?而且,在 avcodec_encode_video() 之后我得到的是一些关于时间戳的警告,并且返回值为零。根据 ffmpeg,函数成功,但零字节意味着 - 什么都没有。顺便说一句,我需要自己构建静态库,因为每隔一段时间我就会发现一个错误。它总是只与 Windows 相关......至少我可以从源头上看出这一点。
    • 顺便说一句,我发现了另一个错误...我尝试完全按照您的描述进行操作。也许一些微小的差异很重要...... av_guess_format("mp4", szFileName, NULL );最终会陷入无限循环。 :-(
    • 同样的无限循环行为发生在 avformat_alloc_output_context2() 函数中。无论如何,我退出了......太多的错误。
    • 你知道为什么 avcodec_encode_video() 返回零吗?
    • @moose - 如果您尝试使用 h264 但未编译,或者未设置任何必需的选项(请参阅 // x264 注释)
    【解决方案2】:

    如果您想在隔行模式下使用 libavcodec+libx264 进行编码,请使用 CODEC_FLAG_INTERLACED_DCT。如果可能的话,您应该直接使用 libx264 或 CLI 程序,这样工作量会减少。

    【讨论】:

      猜你喜欢
      • 2012-08-28
      • 2011-04-02
      • 2011-03-08
      • 1970-01-01
      • 1970-01-01
      • 2012-11-20
      • 2014-02-05
      • 2013-12-21
      • 2015-02-06
      相关资源
      最近更新 更多