Skip to content

Instantly share code, notes, and snippets.

/twopass.cpp Secret

Created March 20, 2014 05:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anonymous/3e01cfdeb64fd577cc48 to your computer and use it in GitHub Desktop.
Save anonymous/3e01cfdeb64fd577cc48 to your computer and use it in GitHub Desktop.
two pass necessary code
AVStream * MyEncoder::add_video_stream(AVFormatContext *oc, AVCodec **codec,
enum AVCodecID codec_id, int width, int height)
{
AVCodecContext *c;
AVStream *st;
/* find the video encoder */
*codec = avcodec_find_encoder(codec_id);
if (!(*codec))
{
fprintf(stderr, "codec not found\n");
exit(1);
}
st = avformat_new_stream(oc, *codec);
if (!st)
{
fprintf(stderr, "Could not alloc stream\n");
exit(1);
}
c = st->codec;
avcodec_get_context_defaults3(c, *codec);
c->codec_id = codec_id;
/* Put sample parameters. */
c->bit_rate = video_bit_rate;
c->bit_rate_tolerance = 1;
/* Resolution must be a multiple of two. */
c->width = width;
c->height = height;
/* timebase: 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
* identical to 1. */
c->gop_size = 50; /* emit one intra frame every twelve frames at most */
if ( codec_id == AV_CODEC_ID_MJPEG )
{
c->pix_fmt = AV_PIX_FMT_YUVJ420P;
}
else
{
c->pix_fmt = STREAM_PIX_FMT; // AV_PIX_FMT_YUV420P
}
if (c->codec_id == AV_CODEC_ID_MPEG2VIDEO) {
/* just for testing, we also add B frames */
c->max_b_frames = 2;
}
if (c->codec_id == AV_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;
}
/* Some formats want stream headers to be separate. */
if (oc->oformat->flags & AVFMT_GLOBALHEADER)
c->flags |= CODEC_FLAG_GLOBAL_HEADER;
if ( twoPassEncoding == CODEC_FLAG_PASS1 ||
twoPassEncoding == CODEC_FLAG_PASS2 )
{
c->flags |= twoPassEncoding;
char logfilename[1024] = "";
char logfile_prefix[90] = "ffmpeg2pass";
sprintf(logfilename, "%s-%d.log",
logfile_prefix ? logfile_prefix :
"ffmpeg2pass",
0);
if ( codec_id == AV_CODEC_ID_H264 )
{
av_dict_set(&opts, "stats", logfilename, AV_DICT_DONT_OVERWRITE);
}
else
{
if (c->flags & CODEC_FLAG_PASS2)
{
//int r = av_dict_set(&this->opts, "flags", "+pass2", AV_DICT_APPEND);
char *logbuffer;
size_t logbuffer_size;
if (cmdutils_read_file(logfilename, &logbuffer, &logbuffer_size) < 0)
{
av_log(NULL, AV_LOG_FATAL, "Error reading log file '%s' for pass-2 encoding\n",
logfilename);
//exit_program(1);
}
c->stats_in = logbuffer;
}
if (c->flags & CODEC_FLAG_PASS1)
{
//int r = av_dict_set(&this->opts, "flags", "+pass1", AV_DICT_APPEND);
FILE* f = fopen(logfilename, "wb");
if (!f)
{
av_log(NULL, AV_LOG_FATAL, "Cannot write log file '%s' for pass-1 encoding: %s\n",
logfilename, strerror(errno));
//exit_program(1);
}
this->logfile = f;
}
}
}
return st;
}
void MyEncoder::write_video_frame(AVFormatContext *oc, AVStream *st, AVFrame *srcFrame)
{
if ( oc->pb == NULL ) return;
char str[90]="";
if ( oc == NULL || st == NULL || srcFrame == NULL )
{
return;
}
int ret;
//....
//...
//...
if (oc->oformat->flags & AVFMT_RAWPICTURE)
{
/* Raw video case - the API will change slightly in the near
* future for that. */
AVPacket pkt;
av_init_packet(&pkt);
pkt.flags |= AV_PKT_FLAG_KEY;
pkt.stream_index = st->index;
pkt.data = dst_picture.data[0];
pkt.size = sizeof(AVPicture);
ret = av_interleaved_write_frame(oc, &pkt);
}
else
{
/* encode the image */
AVPacket pkt = { 0 };
int got_output;
av_init_packet(&pkt);
pkt.data = NULL; // packet data will be allocated by the encoder
pkt.size = 0;
ret = avcodec_encode_video2(c, &pkt, frame, &got_output);
if (ret < 0)
{
fprintf(stderr, "Error encoding video frame\n");
//exit(1);
}
static int64_t tempPts = 0;
static int64_t tempDts = 0;
/* If size is zero, it means the image was buffered. */
if (!ret && got_output && pkt.size)
{
/* rescale output packet timestamp values from codec to stream timebase */
pkt.pts = av_rescale_q_rnd(pkt.pts, c->time_base, st->time_base, (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
pkt.dts = av_rescale_q_rnd(pkt.dts, c->time_base, st->time_base, (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
pkt.duration = av_rescale_q(pkt.duration, c->time_base, st->time_base);
pkt.stream_index = st->index;
if (c->coded_frame->key_frame)
pkt.flags |= AV_PKT_FLAG_KEY;
int sz =pkt.size;
/* Write the compressed frame to the media file. */
ret = av_interleaved_write_frame(oc, &pkt);
if ( ret < 0 )
{
}
sz = pkt.size;
totalPacketsSize += pkt.size;
/* if two pass, output log */
if (this->logfile && c->stats_out)
{
fprintf(this->logfile, "%s", c->stats_out);
}
}
else
{
ret = 0;
}
av_free_packet(&pkt);
}
//...
//...
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment