[libav-api] Difficulties with the encoding raw YUV frames by H.264

Рахимбаев Динар Rakhimbaev.Dinar at cg.ru
Thu Dec 1 09:02:00 CET 2011


Hello list! J

I get raw YUV420p frames from webcam, encode them using h264 encoder and output them into file named 'encoded.mpg'. 

When I try to play the output file, I find that only two frames are written into it. Also it must be noted that I had 'non-strictly-monotonic PTS' warning messages. I got rid of these messages writing code that calculates current picture PTS like this:

 

->>>> picture->pts = frame_count * 40 * 90;

      int out_size = avcodec_encode_video(c, video_outbuf, video_outbuf_size, picture);

 

But to me it seems strange that I must specify PTS value for frames.

Here is my code based on 'output-example.c'. I've removed the code related to audio and brought together the code from all 'output-example.c' functions.

 

Could you take a look on my code and give some advices on my problem please? )

 

/* 5 seconds stream duration */

#define STREAM_DURATION   5.0

#define STREAM_FRAME_RATE 25 /* 25 images/s */

#define STREAM_NB_FRAMES  ((int)(STREAM_DURATION * STREAM_FRAME_RATE))

#define STREAM_PIX_FMT PIX_FMT_YUV420P /* default pix_fmt */

 

static int sws_flags = 4;//SWS_BICUBIC;

 

const int kgWidth = 960, kgHeight = 540;

 

AVFrame *alloc_picture(enum PixelFormat pix_fmt, int width, int height)

{

    AVFrame *picture;

    uint8_t *picture_buf;

    int size;

 

    picture = avcodec_alloc_frame();

    if (!picture)

        return NULL;

    size = avpicture_get_size(pix_fmt, width, height);

    picture_buf = (uint8_t*)av_malloc(size);

    if (!picture_buf) {

        av_free(picture);

        return NULL;

    }

    avpicture_fill((AVPicture *)picture, picture_buf,

                   pix_fmt, width, height);

    return picture;

}

 

int main(int argc, char* argv[])

{

      jthread::JMutex jm;

      jm.Init();

 

      KINECT_GRABBER_OPTIONS deviceOpt;

 

      deviceOpt.MinDepth = 0;

      deviceOpt.MaxDepth = 400;

      deviceOpt.UseGaussianBlur = false;

      deviceOpt.BlurRadius = 0;

      deviceOpt.SmoothFramesCount = 1;

      deviceOpt.VertBlurRadius = 0;

      deviceOpt.VertBlurDiff = 20;

      deviceOpt.HeightOffset = 75;

      deviceOpt.Horizontal = 0;

      deviceOpt.Vertical = 0;

      deviceOpt.Zoom = 1;

      deviceOpt.CutOff = false;

 

      char* filename = argv[1];

 

      // Register all formats and codecs

     av_register_all();

      avformat_network_init();

 

      /* allocate the output media context */

    AVFormatContext *oc = avformat_alloc_context();

    if (!oc) {

        fprintf(stderr, "Memory error\n");

            getc(stdin);

        exit(1);

    }

 

      /* auto detect the output format from the name */

      oc->oformat = av_guess_format("mp4", NULL, NULL);

    if (!oc->oformat) {

        fprintf(stderr, "Could not find suitable output format\n");

            getc(stdin);

        exit(1);

    }

 

      _snprintf(oc->filename, sizeof(oc->filename), "%s", filename);

 

      // Find the encoder for the video stream

      AVCodec *codec = avcodec_find_encoder(CODEC_ID_H264);

    if (!codec) {

        fprintf(stderr, "codec not found\n");

            getc(stdin);

        exit(1);

    }

      

      // Add the video stream where we'll save the pictures

      AVStream *video_st = avformat_new_stream(oc, codec);

      video_st->avg_frame_rate.num = 1;

      video_st->avg_frame_rate.den = 25;

      /* Set the codec of our stream.*/

      AVCodecContext* c = video_st->codec;

    c->bit_rate = 10000000;

    c->width = kgWidth;

    c->height = kgHeight;

      c->bits_per_raw_sample = c->width * c->height * 3 / 2 * 8;

    /* frames per second */

    c->time_base.num = 1;

      c->time_base.den = STREAM_FRAME_RATE;

    c->gop_size = 25; /* emit one intra frame every ten frames */

    c->pix_fmt = PIX_FMT_YUV420P;

 

      c->bit_rate_tolerance = (int) (128000.f * 0.20f);

      c->rc_max_rate = 10;

      c->b_frame_strategy = 0;

      c->coder_type = 0;

      c->me_cmp = 256;

      c->me_range = 16;

      c->qmin = 10;

      c->qmax = 51;

      c->scenechange_threshold = 40;

      c->flags |= CODEC_FLAG_LOOP_FILTER;

      c->me_method = ME_HEX;

      c->me_subpel_quality = 7;

 

 

      c->i_quant_factor = 0.71;

      c->qcompress = 0.6;

      c->max_qdiff = 4;

      c->directpred = 1; 

      c->keyint_min = 25;

      c->partitions |= X264_PART_I4X4 + X264_PART_P8X8 + X264_PART_P4X4 + X264_PART_P8X8 + X264_PART_B8X8; 

      c->refs = 5;    

      c->trellis = 1; 

      c->flags2|= CODEC_FLAG2_MIXED_REFS;  

      c->weighted_p_pred = 2; 

      c->pix_fmt = PIX_FMT_YUV420P;

      c->profile = FF_PROFILE_H264_BASELINE;

      //av_opt_set(c->priv_data, "preset", "slow", 0);

 

      // Some formats want stream headers to be separate

      if(oc->oformat->flags & AVFMT_GLOBALHEADER) {

            video_st->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;

      }

 

      /* set the output parameters (must be done even if no

       parameters). */

    if (av_set_parameters(oc, NULL) < 0) {

        fprintf(stderr, "Invalid output format parameters\n");

        exit(1);

    }

 

      av_dump_format(oc, 0, filename, 1);

 

    // Open codec

      if(avcodec_open(c, codec) < 0) {

        fprintf(stderr, "could not open codec\n");

            getc(stdin);

        exit(1);

    }

 

      uint8_t* video_outbuf = NULL;

      int video_outbuf_size = 0;

    if (!(oc->oformat->flags & AVFMT_RAWPICTURE)) {

        /* allocate output buffer */

        /* XXX: API change will be done */

        /* buffers passed into lav* can be allocated any way you prefer,

           as long as they're aligned enough for the architecture, and

           they're freed appropriately (such as using av_free for buffers

           allocated with av_malloc) */

      video_outbuf_size = avpicture_get_size(c->pix_fmt, c->width, c->height);

        video_outbuf = (uint8_t*)av_malloc(video_outbuf_size);

    }

 

      /* allocate the encoded raw picture */

    AVFrame* picture = alloc_picture(c->pix_fmt, c->width, c->height);

    if (!picture) {

        fprintf(stderr, "Could not allocate picture\n");

        exit(1);

    }

 

      /* open the output file, if needed */

    if (!(oc->oformat->flags & AVFMT_NOFILE)) {

        if (avio_open(&oc->pb, filename, AVIO_FLAG_WRITE) < 0) {

            fprintf(stderr, "Could not open '%s'\n", filename);

                  getc(stdin);

            exit(1);

        }

    }

 

      /* Write the stream header, if any */

      if (av_write_header(oc)<0)

      {

            fprintf(stderr, "Could not write header\n");

            getc(stdin);

        exit(1);

      }

 

      CImageDepthGrabber inputGrabber( jm );

      if( !inputGrabber.InitImage() || !inputGrabber.InitDepth( deviceOpt ) ) {

            std::cerr << inputGrabber.GetErrorString() << std::endl;

            getc(stdin);

            return -1;

      };

 

      int frame_count = 0;

 

      while(true) {

            double video_pts = (double)video_st->pts.val * video_st->time_base.num / video_st->time_base.den;

            if (video_pts >= STREAM_DURATION)

            break;

            if (frame_count >= STREAM_NB_FRAMES) {

                  /* no more frame to compress. The codec has a latency of a few

                     frames if using B frames, so we get the last frames by

                     passing the same picture again */

            } 

            else {

                  // Here I capture one frame from webcam

                  inputGrabber.yv12GetDepthImage(deviceOpt, picture->data[0]);

            }

 

            picture->pts = frame_count * 40 * 90;

            int out_size = avcodec_encode_video(c, video_outbuf, video_outbuf_size, picture);

            

            int ret = 0;

            /* if zero size, it means the image was buffered */

            if (out_size > 0) {

                  AVPacket pkt;

                  av_init_packet(&pkt);

 

                  if (c->coded_frame && c->coded_frame->pts != AV_NOPTS_VALUE) {

                        pkt.pts= av_rescale_q(c->coded_frame->pts, c->time_base, video_st->time_base);

                        //pkt.dts = frame_count * 40 * 90;

                        //pkt.dts= AV_NOPTS_VALUE;

                  }

                  //if(pkt.pts == AV_NOPTS_VALUE && pkt.dts == AV_NOPTS_VALUE && !(oc->oformat->flags & AVFMT_NOTIMESTAMPS)) 

   //             pkt.dts= 0;

                  if(video_st->codec->coded_frame->key_frame) {

                        pkt.flags |= AV_PKT_FLAG_KEY;

                  }

                  pkt.stream_index= video_st->index;

                  pkt.data= video_outbuf;

                  pkt.size= out_size;

 

                  /* write the compressed frame in the media file */

                  ret = av_interleaved_write_frame(oc, &pkt);

                  //ret = av_write_frame(oc, &pkt);

                  out_size = 0;

            } else {

                  ret = 0;//out_size;

            }

 

            if (ret != 0) {

                  fprintf(stderr, "Error while writing video frame\n");

                  getc(stdin);

                  exit(1);

            }

            frame_count++;

      }

 

      /* write the trailer, if any.  the trailer must be written

     * before you close the CodecContexts open when you wrote the

     * header; otherwise write_trailer may try to use memory that

     * was freed on av_codec_close() */

    av_write_trailer(oc);

 

    /* close each codec */

    avcodec_close(video_st->codec);

    av_free(picture->data[0]);

    av_free(picture);

    av_free(video_outbuf);

 

    /* free the streams */

    for(int i = 0; i < oc->nb_streams; i++) {

        av_freep(&oc->streams[i]->codec);

        av_freep(&oc->streams[i]);

    }

 

    if (!(oc->oformat->flags & AVFMT_NOFILE)) {

        /* close the output file */

        avio_close(oc->pb);

    }

 

    /* free the stream */

    av_free(oc);

}

 

Best regards, Dinar!

 

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.libav.org/pipermail/libav-api/attachments/20111201/2961ba75/attachment-0001.html>


More information about the libav-api mailing list