I'm trying to write a video recorder class with ffmpeg, but video file generate have a issue. In every record, the second 1 of the video is a dark frame, and the second 2 is single frame, repeated 25 times. After that, the video runs normal. If I record a video during 10 seconds, the video file will have 12 seconds (2 first second with this issue).
This is my code to start and record the frames:
#include <iostream>
#include <sstream>
#include <string>
#include <iomanip>
#include <thread>
extern "C" {
#include <libavformat/avformat.h>
}
bool recording;
const std::string recordFileName = "video.avi";
std::string camera_address;
std::thread recordingThread;
AVFormatContext* inputFormatContext;
AVOutputFormat* outputFormat;
AVFormatContext* outputFormatContext;
AVStream* outputVideoStream;
bool VideoRecorder::start_record()
{
if (!recording) {
AVDictionary* options = nullptr;
av_dict_set(&options, "rtsp_transport", "udp", 0);
if (avformat_open_input(&inputFormatContext, camera_address.c_str(), nullptr, &options) != 0) {
std::cerr << "Error opening input stream." << std::endl;
return false;
}
if (avformat_find_stream_info(inputFormatContext, nullptr) < 0) {
std::cerr << "Error finding stream information." << std::endl;
avformat_close_input(&inputFormatContext);
return false;
}
// Open output file AVI
if (avformat_alloc_output_context2(&outputFormatContext, outputFormat, "avi", recordFileName.c_str()) < 0) {
std::cerr << "Error allocating output context." << std::endl;
avformat_close_input(&inputFormatContext);
return false;
}
// Add a new video stream to the output file
outputVideoStream = avformat_new_stream(outputFormatContext, nullptr);
if (!outputVideoStream) {
std::cerr << "Error creating output video stream." << std::endl;
avformat_close_input(&inputFormatContext);
avformat_free_context(outputFormatContext);
return false;
}
if (avcodec_parameters_copy(outputVideoStream->codecpar, inputFormatContext->streams[0]->codecpar) < 0) {
std::cerr << "Error copying codec parameters." << std::endl;
avformat_close_input(&inputFormatContext);
avformat_free_context(outputFormatContext);
return false;
}
// Open the output file for writing
if (avio_open(&outputFormatContext->pb, recordFileName.c_str(), AVIO_FLAG_WRITE) < 0) {
std::cerr << "Error opening output file for writing." << std::endl;
avformat_close_input(&inputFormatContext);
avformat_free_context(outputFormatContext);
return false;
}
// Write output file header
if (avformat_write_header(outputFormatContext, nullptr) < 0) {
std::cerr << "Error writing output file header." << std::endl;
avformat_close_input(&inputFormatContext);
avformat_free_context(outputFormatContext);
return false;
}
recording = true;
recordingThread = std::thread(&VideoRecorder::record_video, this);
std::cout << "Recording started." << std::endl;
return true;
}
return false;
}
bool VideoRecorder::record_video()
{
if (recording) {
AVPacket packet;
while (recording && av_read_frame(inputFormatContext, &packet) >= 0) {
AVStream* in_stream = inputFormatContext->streams[packet.stream_index];
AVStream* out_stream = outputFormatContext->streams[0];
// Adjustment of DTS and PTS to ensure increasing monoticity
if (packet.pts != AV_NOPTS_VALUE) {
packet.pts = av_rescale_q_rnd(packet.pts, in_stream->time_base, out_stream->time_base, AVRounding(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
}
if (packet.dts != AV_NOPTS_VALUE) {
packet.dts = av_rescale_q_rnd(packet.dts, in_stream->time_base, out_stream->time_base, AVRounding(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
}
packet.duration = av_rescale_q(packet.duration, in_stream->time_base, out_stream->time_base);
packet.stream_index = 0;
av_interleaved_write_frame(outputFormatContext, &packet);
av_packet_unref(&packet);
}
return true;
}
std::cerr << "Error recording video. Recording not started or already stopped." << std::endl;
return false;
}
I know this extra 2 seconds of frames comes from avformat_open_input(&inputFormatContext, camera_address.c_str(), nullptr, &options) and avformat_find_stream_info(inputFormatContext, nullptr) execution, this fuction execute in around 2-3 seconds, and at this time, wrong packets are writen to inputFormatContext.
I've already tried:
avformat_flush(inputFormatContext);;
while (av_read_frame(inputFormatContext, &packet) >= 0) { av_packet_unref(&packet); };
Write the first 2 seconds in another file;
Cut the first 2 seconds from the file (this works in the terminal, but not in code)
void VideoRecorder::cut_video() {
std::string outputFileName = "cut_" + recordFileName;
std::string command = "ffmpeg -ss 2 -i " + recordFileName + " -c copy " + outputFileName;
int result = std::system(command.c_str());
if (result == 0) {
std::cout << "Video cut successfully." << std::endl;
std::remove(recordFileName.c_str());
std::cout << "Original video file deleted." << std::endl;
} else {
std::cerr << "Error cutting video." << std::endl;
}
}
;
Verify packet.dts and packet.pts, if wrong values is find, don't write the packet;
None of this solved my problem. I just need a way to remove this first 2 seconds of wrong frames from my video.