Hello,
I need to encode a video with the Xvid codec, but run into the problem
that avcodec_encode_video() keeps returning -1.
Since I work on Windows, I compiled the Xvid codec and than ffmpeg and
avcodec.lib with mingw using the following configure:
$ ./configure --enable-shared --enable-memalign-hack
--prefix=../../libffmpeg.xvid --extra-ldflags="-Wl,-add-std
call-alias,-L../../libxvid/lib" --extra-cflags="-I../../libxvid/include"
--enable-libxvid --enable-gpl --enable-
encoder=CODEC_ID_XVID
Using ffmpeg.exe, I'm able to convert an mpeg-video to a Xvid-coded avi, so
the generated avcodec.lib seems to support Xvid.
Than I build a class based on output_example.c to write a Xvid-coded video
directly. Using any other codec (e.g. CODEC_ID_MPEG4) works fine, but
setting
tAVOutputFormat->video_codec = CODEC_ID_XVID results in
avcodec_encode_video() returning -1.
I assume that I have to set other values in the AVCodecContext to make the
codec work, but I didn't find any documentation or example on it.
Regards,
Torsten
Here is the relevant code:
int CMpegEncoderFFMPEG::init(
int pBitrate,
int pWidth,
int pHeight,
int pFramesPerSecond,
bool pWriteFile )
{
// initialize libavcodec, and register all codecs and formats
avcodec_init();
avcodec_register_all();
av_register_all();
const char* tFilename = "test.avi";
mWriteFile = pWriteFile;
// auto detect the output format from the name; default is mpeg
AVOutputFormat* tAVOutputFormat = guess_format(NULL, tFilename, NULL);
if( !tAVOutputFormat )
{
printf("Could not deduce output format from file extension: using
MPEG.\n");
tAVOutputFormat = guess_format("mpeg", NULL, NULL);
}
if( !tAVOutputFormat )
{
fprintf(stderr, "Could not find suitable output format\n");
return 0;
}
// the codec is determined implicitly by the format
// mpeg -> CODEC_ID_MPEG1VIDEO (1)
// mp4 -> CODEC_ID_MPEG4 (13)
// avi -> CODEC_ID_MPEG4 (13)
// set XVID codec explicitly
tAVOutputFormat->video_codec = CODEC_ID_XVID;
// allocate the output media context
mAVFormatContext = avformat_alloc_context();
if( !mAVFormatContext )
{
fprintf(stderr, "Memory error\n");
return 0;
}
mAVFormatContext->oformat = tAVOutputFormat;
sprintf_s( mAVFormatContext->filename, sizeof(mAVFormatContext->filename),
"%s", tFilename );
// add the audio and video streams using the default format codecs and
initialize the codecs
if( tAVOutputFormat->video_codec != CODEC_ID_NONE )
mVideoStream = addVideoStream( mAVFormatContext,
tAVOutputFormat->video_codec, pBitrate, pWidth, pHeight, pFramesPerSecond );
if( tAVOutputFormat->audio_codec != CODEC_ID_NONE)
mAudioStream = addAudioStream( mAVFormatContext,
tAVOutputFormat->audio_codec );
// set the output parameters (must be done even if no parameters)
if (av_set_parameters(mAVFormatContext, NULL) < 0)
{
fprintf(stderr, "Invalid output format parameters\n");
return 0;
}
dump_format( mAVFormatContext, 0, tFilename, 1 );
// now that all the parameters are set, we can open the audio and video
codecs and allocate the necessary encode buffers
if( mVideoStream )
openVideo( mAVFormatContext, mVideoStream );
if( mAudioStream )
openAudio( mAVFormatContext, mAudioStream );
// open the output file
if( mWriteFile )
{
if( url_fopen(&mAVFormatContext->pb, tFilename, URL_WRONLY) < 0 )
{
fprintf( stderr, "Could not open '%s'\n", tFilename );
return 0;
}
// write the stream header, if any
av_write_header(mAVFormatContext);
}
return 0;
}
AVStream* CMpegEncoderFFMPEG::addVideoStream(
AVFormatContext *oc,
int codec_id,
int pBitrate,
int pWidth,
int pHeight,
int pFramesPerSecond )
{
AVStream *tAVStream = av_new_stream(oc, 0);
if( !tAVStream )
{
fprintf(stderr, "Could not alloc stream\n");
return 0;
}
AVCodecContext *c = tAVStream->codec;
c->codec_id = (CodecID) codec_id;
c->codec_type = CODEC_TYPE_VIDEO;
// put sample parameters
c->bit_rate = pBitrate;
// resolution must be a multiple of two
c->width = pWidth;
c->height = pHeight;
// time base: this is the fundamental unit of time (in seconds) in terms
of which frame timestamps are represented
// for fixed-fps content, timebase should be 1/framerate and timestamp
increments should be identically 1
c->time_base.den = pFramesPerSecond;
c->time_base.num = 1;
c->gop_size = 12; // emit one intra frame every twelve frames at most
c->pix_fmt = STREAM_PIX_FMT;
if (c->codec_id == CODEC_ID_MPEG2VIDEO)
{
// just for testing, we also add B frames
c->max_b_frames = 2;
}
if (c->codec_id == CODEC_ID_MPEG1VIDEO)
{
// Needed to avoid using macroblocks in which some coeffs overflow.
// This does not happen with normal video, it just happens here as
// the motion of the chroma plane does not match the luma plane.
c->mb_decision=2;
}
if (c->codec_id == CODEC_ID_XVID )
{
c->pix_fmt = PIX_FMT_YUV420P; // ???
}
// some formats want stream headers to be separate
if(oc->oformat->flags & AVFMT_GLOBALHEADER)
c->flags |= CODEC_FLAG_GLOBAL_HEADER;
return tAVStream;
}
int CMpegEncoderFFMPEG::encodeVideoFrame(
AVFormatContext* pAVFormatContext,
AVStream *st )
{
int tOutputSize;
AVCodecContext *c = st->codec;
if( pAVFormatContext->oformat->flags & AVFMT_RAWPICTURE )
{
// raw video case
if( mWriteFile )
{
AVPacket pkt;
av_init_packet(&pkt);
pkt.flags |= PKT_FLAG_KEY;
pkt.stream_index= st->index;
pkt.data= (uint8_t *)mAVFrame;
pkt.size= sizeof(AVPicture);
int ret = av_interleaved_write_frame( pAVFormatContext, &pkt );
}
}
else
{
// encode the image
tOutputSize = avcodec_encode_video( c, mVideoOutputBuffer,
mVideoOutputBufferSize, mAVFrame );
// if zero size, it means the image was buffered
if( mWriteFile && tOutputSize>0 )
{
AVPacket pkt;
av_init_packet(&pkt);
if( c->coded_frame->pts != AV_NOPTS_VALUE )
pkt.pts= av_rescale_q(c->coded_frame->pts, c->time_base,
st->time_base);
if( c->coded_frame->key_frame )
pkt.flags |= PKT_FLAG_KEY;
pkt.stream_index = st->index;
pkt.data = mVideoOutputBuffer;
pkt.size = tOutputSize;
int ret = av_interleaved_write_frame(pAVFormatContext, &pkt);
}
}
mFrameCount++;
return tOutputSize;
}
_______________________________________________
libav-user mailing list
[email protected]
https://lists.mplayerhq.hu/mailman/listinfo/libav-user