#include "encoder.h" #include int encoder_init (struct Encoder *encoder, const AVCodecParameters *codecpar, AVDictionary **opts) { /* NOTE: While encoder->time_base "MUST be set by user" when encoding * (quoted from the official FFMPEG documentation), avcodec_open2 actually * discard it's value and set it to '1/sample_rate'. * * NOTE: The assert at the end of this section serves to protect cybd in * case the FFMPEG devs update their code to implement some funny behaviors. */ int err; AVCodecContext *avctx; const AVCodec *codec; if ((codec = avcodec_find_encoder(codecpar->codec_id)) == NULL) { err = AVERROR_ENCODER_NOT_FOUND; goto error; } if ((avctx = avcodec_alloc_context3(codec)) == NULL) return AVERROR(ENOMEM); if ((err = avcodec_parameters_to_context(avctx, codecpar)) < 0) goto error; if ((err = avcodec_open2(avctx, codec, opts))) goto error; /* Because some code rely on avctx's time base to be 1/sample_rate, and * because this behavious currently appears undocumented, I placed some * assert here to catch up if anything changes up with ffmpeg. */ assert(avctx->time_base.num == 1); assert(avctx->time_base.den == avctx->sample_rate); encoder->avctx = avctx; encoder->pts = 0; return 0; error: avcodec_free_context(&avctx); return err; } int encoder_init_for_stream (struct Encoder *encoder, const AVStream *stream, AVDictionary **opts) { return encoder_init(encoder, stream->codecpar, opts); } int encoder_send (struct Encoder *encoder, const AVFrame *frame) { return avcodec_send_frame(encoder->avctx, frame); } int encoder_convert (struct Encoder *encoder, AVPacket *pkt_out) { int err; err = avcodec_receive_packet(encoder->avctx, pkt_out); if (err < 0) return err; // Manually setting pts because FFMPEG doesn't do it consistantly //pkt_out->pts = encoder->pts; //encoder->pts += pkt_out->duration; return 0; } void encoder_free (struct Encoder *encoder) { avcodec_free_context(&encoder->avctx); }