-
-
Save anonymous/3e01cfdeb64fd577cc48 to your computer and use it in GitHub Desktop.
two pass necessary code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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