x264 & libavcodec - PullRequest
       40

x264 & libavcodec

2 голосов
/ 10 декабря 2011

Через некоторое значительное время, пытаясь собрать статическую библиотеку ffmpeg с кодировщиком x264 в Windows, я потратил еще немного времени на написание некоторого примера с ней.Конечно, существует множество «инструкций» о том, как создавать, как использовать, бла-бла ... Но ни одна из них не работает на Windows.Я думаю, что парни из Linux находятся в лучшем положении здесь.Теперь вопрос на миллион долларов: «Какова цель всего этого?».Мало того, что это бесполезно в Windows, но я мог бы купить какую-нибудь стороннюю библиотеку, которая действительно работает.

Если кто-то скажет: «Но это работает!».Я должен сказать, дай мне рабочее доказательство.Меня не волнует 200х100 при 10 кадрах в секунду.Мне не нужна H264 для этого.Покажите мне, как сжать одну секунду 1080i кадры.Это H264, он кроссплатформенный (звучит смешно, если вы спросите меня), Google использует его (он должен быть идеальным, верно?), Еще немного хиппинга здесь ...

Ответы [ 2 ]

3 голосов
/ 10 декабря 2011

Во-первых, не пытайтесь строить на Windows - особенно если вы используете VS - получите его от здесь

Тогда последовательность выглядит примерно так:

 // 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;
}
0 голосов
/ 25 января 2012

Если вы хотите кодировать с помощью libavcodec + libx264 в чересстрочном режиме, используйте CODEC_FLAG_INTERLACED_DCT. Если возможно, вам следует напрямую использовать libx264 или программу CLI, это меньше работает.

...