On Wed, May 6, 2009 at 2:14 PM, Tom Goossens <[email protected]> wrote:
> Dear list,
>
> Recently I made a c++ implementation of an mpeg4 encoder heavily based on
> the libavcodec/api-example.c. The encoder works. Hoewever, when I use
> mplayer to play the encoded file there is no time information in the status
> bar. Worse, I think this prohibits me from using seek to go to a specific
> frame in the file.
>
> I've set the timbase with
> m_pCodecCtx->time_base.num = 1;
> m_pCodecCtx->time_base.den = 25;
>
> Do I need to put in other information in order to get the timing
> information in the file? Must I explicitly set the pts for each frame? This
> does no seem to work with AVFrame->pts.
>
> So far I've had little luck in finding an answer here in the list or
> elsewhere. Any help would be greatly appreciated.
>
> Kind regards,
> Tom Goos
>
Hello all,
I'm including the c++ class I made for encoding my video (It's mostly coming
from a capture card).
I hope anyone can give a suggestion as to what I'm missing to get the
correct timing information in the MPEG4 file.
Kind regards,
Tom
PS I left out the header because most of it is pretty obvious. I can post it
if requested.
#include "stdio.h"
#include "string.h"
#include "ImageBaseClass.h"
#include "CFfmpegEnc.h"
extern "C" {
#include "ffmpeg/avcodec.h"
#include "ffmpeg/avformat.h"
#include "ffmpeg/swscale.h"
#include "ffmpeg/rational.h"
}
CFfmpegEnc::CFfmpegEnc() {
m_pCodec = NULL;
m_pCodecCtx = NULL;
m_pAVFrame = NULL;
m_pFile = NULL;
m_pOutbuf = NULL;
m_outbuf_size = 0;
m_out_size = 0;
}
CFfmpegEnc::~CFfmpegEnc() {
close();
}
int CFfmpegEnc::init(const char *filename, enum CodecID codecId, int width,
int height) {
uint8_t * picture_buf;
int size;
/* must be called before using avcodec lib */
avcodec_init();
/* register all the codecs */
avcodec_register_all();
av_register_all();
/* find the video encoder */
m_pCodec = avcodec_find_encoder(codecId); // I'm using CODEC_ID_MPEG4
if (!m_pCodec) {
fprintf(stderr, "codec not found\n");
return 1;
}
m_pCodecCtx = avcodec_alloc_context();
m_pAVFrame = avcodec_alloc_frame();
/* put sample parameters */
m_pCodecCtx->bit_rate = 4000000;
/* resolution must be a multiple of two */
m_pCodecCtx->width = width;
m_pCodecCtx->height = height;
/* frames per second */
m_pCodecCtx->time_base.num = 1;
m_pCodecCtx->time_base.den = 25;
m_pCodecCtx->gop_size = 10; /* emit one intra frame every ten frames */
m_pCodecCtx->max_b_frames = 1;
m_pCodecCtx->pix_fmt = PIX_FMT_YUV420P;
/* open it */
if (avcodec_open(m_pCodecCtx, m_pCodec) < 0) {
fprintf(stderr, "could not open codec\n");
return 2; // Could not open codec
}
m_pFile = fopen(filename, "wb");
if (!m_pFile) {
fprintf(stderr, "could not open file %s\n", filename);
return 3;
}
/* alloc image and output buffer */
m_outbuf_size = 1000000;
m_pOutbuf = (uint8_t*)malloc(m_outbuf_size);
size = m_pCodecCtx->width * m_pCodecCtx->height;
picture_buf = (uint8_t*)malloc((size * 3) / 2); /* size for YUV 420 */
m_pAVFrame->data[0] = picture_buf;
m_pAVFrame->data[1] = m_pAVFrame->data[0] + size;
m_pAVFrame->data[2] = m_pAVFrame->data[1] + size / 4;
m_pAVFrame->linesize[0] = m_pCodecCtx->width;
m_pAVFrame->linesize[1] = m_pCodecCtx->width / 2;
m_pAVFrame->linesize[2] = m_pCodecCtx->width / 2;
return 0;
}
int CFfmpegEnc::close() {
uint8_t outbuf[4];
/* add sequence end code to have a real mpeg file */
outbuf[0] = 0x00;
outbuf[1] = 0x00;
outbuf[2] = 0x01;
outbuf[3] = 0xb7;
if(m_pFile) // !! When error during init, m_pFile will be NULL
{
fwrite(outbuf, 1, 4, m_pFile);
fclose(m_pFile);
}
avcodec_close(m_pCodecCtx);
av_freep(&m_pCodecCtx);
av_freep(&m_pAVFrame);
SAFE_DELETE(m_pOutbuf);
printf("video file closed\n");
return 0;
}
int CFfmpegEnc::addFrame(CImageBaseClass * image){
AVFrame * AVFrame444;
AVFrame444 = avcodec_alloc_frame();
AVFrame444->data[0] = (uint8_t *)image->GetBuffer(0);
AVFrame444->data[1] = (uint8_t *)image->GetBuffer(2);
AVFrame444->data[2] = (uint8_t *)image->GetBuffer(1);
AVFrame444->linesize[0] = m_pCodecCtx->width;
AVFrame444->linesize[1] = m_pCodecCtx->width;
AVFrame444->linesize[2] = m_pCodecCtx->width;
// the next section comes from
//
http://web.me.com/dhoerl/Home/Tech_Blog/Entries/2009/1/22_Revised_avcodec_sample.c.html
static struct SwsContext *img_convert_ctx;
if(img_convert_ctx == NULL) {
int w = m_pCodecCtx->width;
int h = m_pCodecCtx->height;
img_convert_ctx = sws_getContext(w, h, PIX_FMT_YUV444P, //src
w, h, PIX_FMT_YUV420P, //dst
SWS_BICUBIC,
NULL, NULL, NULL);
if(img_convert_ctx == NULL) {
fprintf(stderr, "Cannot initialize the conversion context!\n");
exit(1);
}
}
// function template, for reference
// int sws_scale(struct SwsContext *context, uint8_t* src[], int
srcStride[], int srcSliceY,
// int srcSliceH, uint8_t* dst[], int
dstStride[]);
int ret = sws_scale(img_convert_ctx, AVFrame444->data,
AVFrame444->linesize, 0,
m_pCodecCtx->height, m_pAVFrame->data, m_pAVFrame->linesize);
(void)ret; // unused variable
// encode the image
m_out_size = avcodec_encode_video(m_pCodecCtx, m_pOutbuf, m_outbuf_size,
m_pAVFrame);
// printf("encoding frame (size=%5d)\n", out_size);
fwrite(m_pOutbuf, 1, m_out_size, m_pFile);
delete(AVFrame444);
return 0;
}
_______________________________________________
libav-user mailing list
[email protected]
https://lists.mplayerhq.hu/mailman/listinfo/libav-user