Question

After some considerable amount of time while trying to build the ffmpeg static library with the x264 encoder on Windows, I have spent some more time for writing some example with it. Of course, there are tons of "instructions" on how to build, how to use, bla bla... But, non of them works on Windows. I guess the Linux guys are in better position here. Now, the zillion dollars question is "What's the purpose of all that?". Not only that this is useless on Windows, but I could have bought some third party library that actually works.

If somebody is about to say "But, it works!". I must say, give me a working proof. I don't care about 200x100 at 10fps. I don't need H264 for that. Show me how to compress a single second of 1080i footage. It's H264, it's crossplatform (sounds funny if you ask me), Google is using it (it has to be perfect, right?), some more hipe here...

Was it helpful?

Solution

Firstly don't try and build on windows - especially if you use VS - get it from here

Then the sequence is something like:

 // 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;
}

Then for each frame

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;
}

OTHER TIPS

If you want to encode with libavcodec+libx264 in interlaced mode, use CODEC_FLAG_INTERLACED_DCT. If possible you should use libx264 or the CLI program directly though, it's less work.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top