Hello,
I have a problem to create application using libav for encoding raw video
with x265.
Below is description of example that I created following encode_video.c
example.
I tried also the encode_example code and I have the same problem.
I used GRAY8 and YUV_420P formats of video frames, I get same results for
both formats.

The problem occurs only in my implementation, command line works fine.
Please help me to understand what is missing in my application

Thanks,
Marina

---------- Forwarded message ----------
From: Marina Vasilevsky <[email protected]>
Date: Sun, Aug 19, 2018 at 11:35 AM
Subject: Encode x265 annexb stream from grayscale images
To: [email protected]


Hello,

Trying to create simple utility that encodes multiple images to x265 annexB
stream.
OS Ubuntu
libav version: 3.4.2

Command line works:
ffmpeg -loglevel 48 -f image2 -s 640x640 -pattern_type sequence
-start_number 180 -i /media/marina/sdxdata/sw/records/pattern/%08d.pgm -c:v
libx265 -preset veryslow -x265-params lossless=1 -vf "format=gray8" -f hevc
out1.bin


Source code - I followed guiding and examples of ffmpeg
avcodec_receive_packet always returns EAGAIN,
When I send null frame, it returns packet - with encoded latest frame.

Attached file is implementation of frame encode and codec init
There is main loop that  calls "AppendFrame" multiple times

Thanks,
Marina
//#include <libavutil/common.h>
//#include <libavutil/mem.h>

#include "rec_svc_enc.h"

CRecSvcEnc::CRecSvcEnc(seastar::logger *pLogger, CRecSvcCfg *pCfg, QObject *parent) : QObject(parent)
{
   m_Cfg = pCfg;
   m_Codec = nullptr;
   m_Logger = pLogger;
   m_frame  = nullptr;
   m_FrameDelayed = false;
}

bool CRecSvcEnc::IsValid()
{
   if(m_Codec == nullptr) {
      return false;
   }
   return true;
}

void CRecSvcEnc::EncStart(CodecParams params)
{   
   avcodec_register_all();
   av_log_set_level (AV_LOG_TRACE);

   m_Codec = avcodec_find_encoder(AV_CODEC_ID_H265);
   if(m_Codec == nullptr) {
      m_Logger->error("{} codec not found\n", FUNCN);
      return;
   }   
   m_CodecCtx= avcodec_alloc_context3(m_Codec);

    AVDictionary * av_dict_opts = nullptr;
    /// encoding nvenc profiles
    //av_dict_set( &av_dict_opts, "loglevel", "48", AV_DICT_MATCH_CASE); /// hq ll lossless losslesshq
    av_dict_set( &av_dict_opts, "preset", "veryslow", AV_DICT_MATCH_CASE); /// hq ll lossless losslesshq
    av_dict_set( &av_dict_opts, "x265-params", "lossless=1:log-level=4",  AV_DICT_MATCH_CASE);
    //av_dict_set( &av_dict_opts, "-f", "image2", AV_DICT_MATCH_CASE);

   /* put sample parameters */
   m_CodecCtx->width = params.width; // /2;
   m_CodecCtx->height = params.heiht; // /2;
   m_CodecCtx->time_base= {1,30};//m_Cfg->GetFrameRate()};
   m_CodecCtx->pix_fmt = AV_PIX_FMT_GRAY8;//params.pixFmt; //AVPixelFormat::AV_PIX_FMT_GRAY8;
   m_CodecCtx->debug = 0xffff;// |= FF_DEBUG_BUFFERS | FF_DEBUG_PICT_INFO | FF_DEBUG_BUGS;
   m_CodecCtx->gop_size = 10;
   //m_CodecCtx->gop_size = 20; /* emit one intra frame every ten frames */
   //m_CodecCtx->max_b_frames=1;

   //m_CodecCtx->properties = FF_CODEC_PROPERTY_LOSSLESS;
   //av_opt_set(m_CodecCtx->priv_data, "preset", "ultrafast", 0);
   /* open it */
   int ret = avcodec_open2(m_CodecCtx, m_Codec, &av_dict_opts);
   if (ret < 0) {
      m_Logger->error("{} could not open codec {}\n", FUNCN, ret);
      m_Codec = nullptr;
      return;
   }

   m_frame = av_frame_alloc();
   if (!m_frame) {
      m_Logger->error("{} Could not allocate video frame\n", FUNCN);
      return;
   }

   m_frame->format = m_CodecCtx->pix_fmt;
   m_frame->width  = m_CodecCtx->width;
   m_frame->height = m_CodecCtx->height;
   m_frame->pts = 1;
   m_frame->display_picture_number = 0;
   //m_frame->linesize = m_frame->width[];
   /* the image can be allocated by any means and av_image_alloc() is
   * just the most convenient way if av_malloc() is to be used */

   ret = av_image_alloc(m_frame->data, m_frame->linesize, m_CodecCtx->width, m_CodecCtx->height,
                            m_CodecCtx->pix_fmt, 32);

   //av_frame_get_buffer(m_frame,32);
   if (ret < 0) {
      m_Logger->error("{} Could not allocate raw picture buffer\n", FUNCN);
      av_frame_free(&m_frame);
      m_frame = nullptr;
      return;
   }
}

void CRecSvcEnc::EncStop()
{
   if(!IsValid())
      return;
   avcodec_close(m_CodecCtx);
   av_free(m_CodecCtx);
}

void CRecSvcEnc::CopyFrame(QImage im)
{
   int Offset = 0;
   const uchar* ba = im.constBits();

   int CopyLen = m_frame->linesize[0]*im.height();
   memcpy(m_frame->data[0], ba,CopyLen);

   return;
   Offset+=CopyLen;

   CopyLen= m_frame->linesize[1]*im.height();
   memcpy(m_frame->data[1], ba+Offset, CopyLen);
   Offset+=CopyLen;

   CopyLen= m_frame->linesize[2]*im.height();
   memcpy(m_frame->data[2], ba+Offset, CopyLen);
}

bool CRecSvcEnc::AppendFrame(QImage im)
{
   bool bRet = true;
   int ret;
   if(!IsValid() || m_frame==nullptr)
      return false;
 //  EncPull();

   if(m_PendingQ.size() >= MAX_PENDING )
      bRet = false;
   else
      m_PendingQ.append(im);
   if(!m_FrameDelayed) {
      im = m_PendingQ.first();
      const uchar* ba = im.constBits();
      //memcpy(m_frame->data[0], ba,m_frame->linesize[0]*m_frame->height);
      //memcpy(m_frame->data[0], ba,im.sizeInBytes());
      CopyFrame(im);
   }

   ret = avcodec_send_frame(m_CodecCtx,m_frame);


#if 0
   av_init_packet(&m_pkt);
   m_pkt.data = nullptr;    // packet data will be allocated by the encoder
   m_pkt.size = 0;
   int gotPkt = 0;
   avcodec_encode_video2(m_CodecCtx,&m_pkt,m_frame,&gotPkt );
#endif
   if (ret < 0) {
      m_Logger->error("{} Error encoding frame {}\n", FUNCN, ret);
      m_FrameDelayed = true;
   }
   else {
      m_FrameDelayed = false;
      m_PendingQ.takeFirst();
      m_frame->pts++;
      m_frame->display_picture_number++;
      EncPull();
   }

   return bRet;
#if 0
   if (gotOutput) {
      m_Logger->trace("{} Write frame  (size={})\n", m_pkt.size);
      ba.append(m_pkt.data, pkt.size);
      av_free_packet(&m_pkt);
   }
#endif
}

void CRecSvcEnc::EncPull()
{
   av_init_packet(&m_pkt);
   m_pkt.data = nullptr;    // packet data will be allocated by the encoder
   m_pkt.size = 0;
   int ret = avcodec_receive_packet(m_CodecCtx, &m_pkt);

   if (ret >= 0) {
      QByteArray ba = QByteArray(((const char*)m_pkt.data), m_pkt.size);
      m_Encoded.append(ba);
      av_packet_unref(&m_pkt);
   }
   else if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) {
      ;
   }


}

void CRecSvcEnc::Save2File()
{   
   int ret = avcodec_send_frame(m_CodecCtx,nullptr);
   EncPull();
   QFile ff("/nvxdata/tmp.bin");
   ff.open(QIODevice::WriteOnly | QIODevice::Truncate);
   ff.write(m_Encoded);
   ff.close();
}
#ifndef REC_SVC_ENC_H
#define REC_SVC_ENC_H

#include <QObject>
#include <QImage>

extern "C" {
#include "libavcodec/avcodec.h"
#include <libavutil/opt.h>
#include <libavutil/imgutils.h>
#include <libavutil/log.h>
}

//#include "libavutil/mathematics.h"

#include "log.hh"
#include "svc_record.h"
#include "rec_svc_cfg.h"

using namespace seastar;
#define MAX_PENDING 50

class CRecSvcEnc : public QObject
{
   Q_OBJECT
public:
   struct CodecParams {
      int width;
      int heiht;
      enum AVPixelFormat pixFmt;
   };
   explicit CRecSvcEnc(seastar::logger *pLogger,CRecSvcCfg *pCfg, QObject *parent = nullptr);
   bool IsValid();
   void EncStart(CodecParams params);
   void EncStop();
   bool AppendFrame(QImage im);
   void EncPull();
   void Save2File();
signals:

public slots:
private:
   AVCodec *m_Codec;
   AVCodecContext *m_CodecCtx;
   seastar::logger *m_Logger;
   QByteArray m_Encoded;
   AVFrame *m_frame;

   bool m_FrameDelayed;
   QList<QImage> m_PendingQ;
   AVPacket m_pkt;
   CRecSvcCfg *m_Cfg;

   void CopyFrame(QImage im);
};

#endif // REC_SVC_ENC_H
_______________________________________________
Libav-user mailing list
[email protected]
http://ffmpeg.org/mailman/listinfo/libav-user

Reply via email to