How do you properly mux an mp4 file with FFmpeg 4? I have an issue with the time base, I'm pretty sure. Using ffprobe, I found encoding 24 frames for a 24 FPS output video which should theoretically produce a 1-second video, instead produces a 4 millisecond, 142.61 FPS video with a bitrate 157326 kb/s. I have been stuck on this for months. What's the issue? How do I fix this?
void Camera::Encode(Frame frame) {
if (av_frame_make_writable(frame_) < 0)
throw std::runtime_error("failed to write to frame");
frame_->data = frame.data;
frame_->pts += av_rescale_q(1, context_->time_base, stream_->time_base);
if (avcodec_send_frame(context_, frame_) < 0)
throw std::runtime_error("failed to send a frame for encoding");
int ret = 0;
AVPacket packet = { 0 };
while (ret >= 0) {
ret = avcodec_receive_packet(context_, &packet);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
break;
else if (ret < 0)
throw std::runtime_error("failed to encode frame");
ret = av_interleaved_write_frame(format_, &packet);
av_packet_unref(&packet);
}
}
void Camera::Start() {
avformat_alloc_output_context2(&format_, NULL, "mp4", output_.c_str());
if (!format_)
throw std::runtime_error("failed to find output format");
stream_ = avformat_new_stream(format_, NULL);
if (!stream_)
throw std::runtime_error("failed to allocate video stream");
stream_->id = format_->nb_streams-1;
stream_->codecpar->codec_id = AV_CODEC_ID_H264;
stream_->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
stream_->codecpar->width = frame.width;
stream_->codecpar->height = frame.height;
stream_->codecpar->bit_rate = 0.28 * fps_ * stream_->codecpar->width *
stream_->codecpar->height;
stream_->codecpar->format = AV_PIX_FMT_YUV420P;
stream_->time_base = av_make_q(1, fps_);
stream_->r_frame_rate = av_make_q(fps_, 1);
stream_->avg_frame_rate = av_make_q(fps_, 1);
AVCodec* codec = avcodec_find_encoder(AV_CODEC_ID_H264);
if (!codec)
throw std::runtime_error("failed to find codec");
context_ = avcodec_alloc_context3(codec);
if (!context_)
throw std::runtime_error("failed to allocate video codec context");
context_->width = stream_->codecpar->width;
context_->height = stream_->codecpar->height;
context_->bit_rate = stream_->codecpar->bit_rate;
context_->time_base = av_make_q(1, fps_);
context_->framerate = av_make_q(fps_, 1);
context_->gop_size = 10;
context_->max_b_frames = 1;
context_->pix_fmt = AV_PIX_FMT_YUV420P;
if (avcodec_open2(context_, codec, NULL) < 0)
throw std::runtime_error("failed to open codec");
if (format_->oformat->flags & AVFMT_GLOBALHEADER)
context_->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
if (!(format_->flags & AVFMT_NOFILE))
if (avio_open(&format_->pb, output_.c_str(), AVIO_FLAG_WRITE) < 0)
throw std::runtime_error("failed to open video file");
if (avformat_write_header(format_, NULL) < 0)
throw std::runtime_error("failed to write headers");
frame_ = av_frame_alloc();
if (!frame_)
throw std::runtime_error("failed to allocate video frame");
frame_->pts = 0;
frame_->width = context_->width;
frame_->height = context_->height;
frame_->format = AV_PIX_FMT_YUV420P;
if (av_frame_get_buffer(frame_, 32) < 0)
throw std::runtime_error("failed to allocate the video frame data");
}
Aucun commentaire:
Enregistrer un commentaire