видео — C ++ RTSP Stream записывает неверную временную базу ffmpeg

Мы получаем поток с камеры через RTSP (Axis Q1755 H264). И через некоторое время мы начинаем записывать поток в файл. Я проверяю видеофайл с помощью ffprobe и понимаю, что время начала — это не время начала записи, а время начала извлечения потока. Мое видео имеет длину 5 секунд, и время начала видео должно быть 0. Но реальное время начала видео составляет 20 секунд. Это приводит к неправильной временной базе. (ffmpeg Версия 3.3.3)

Я пытаюсь исправить это, но теперь у меня есть некоторое время ошибка timebase 1/180000... я пометил свои изменения комментарием (timebase repair logic)

видео по времени

Вывод ffprobe (без логики восстановления временной базы)
Начало выше, чем продолжительность, правильно начало 0 и не 20.080000

Input #0, mov,mp4,m4a,3gp,3g2,mj2, from
'C:\testvideo.mp4':
Metadata:
major_brand     : isom
minor_version   : 512
compatible_brands: isomiso2avc1mp41
encoder         : Lavf57.71.100   Duration: 00:00:05.04, start: 20.080000, bitrate: 2675 kb/s
Stream #0:0(und): Video: h264 (Baseline) (avc1 / 0x31637661), yuvj420p(pc, bt709), 800x450 [SAR 1:1 DAR 16:9], 2670 kb/s, 50.20 fps,
50 tbr, 180k tbn, 360k tbc (default)
Metadata:
handler_name    : VideoHandler

Ошибка после добавления логики восстановления временной базы

[mpeg4 @ 00000178fcb12b40] таймбаз 1/180000 не поддерживается MPEG 4
стандартно, максимальное допустимое значение для знаменателя временной базы
65535 Не удалось открыть кодек «mpeg4»: ошибка не указана
запись

Вот некоторые части моего кода

Start Logic

bool RecordingStreamGrabber::start()
{
CORE_LOG_INFO(m_logger, "Started RecordingStreamGrabber");
if (m_thread == NULL)
{
if (this->prepareInputStream())
{
m_run = true;
m_thread = new std::thread(RecordingStreamGrabber::run, this);
return true;
}
CORE_LOG_ERROR(m_logger, "Error starting RecrodingStreamGrabber");
return false;
}
return false;
}

Подготовить поток ввода / вывода

bool RecordingStreamGrabber::prepareInputStream()
{
CORE_LOG_INFO(m_logger, "Preparing Inputstream for recording: " << m_url);

m_ifmtctx = avformat_alloc_context();
interrupt_recording_nostop = false;
interrupt_recording_timeout = m_timeout; // Timeout in milisekunde
interrupt_recording_starttime = GetTickCount();
m_ifmtctx->interrupt_callback = interrupt_timeout_cb;

if (avformat_open_input(&m_ifmtctx, m_url.c_str(), NULL, NULL) != 0)
{
m_ifmtctx = NULL;
CORE_LOG_ERROR(m_logger, "Error opening recording URL: " << m_url);
return false;
}

interrupt_recording_nostop = true;

if (avformat_find_stream_info(m_ifmtctx, NULL) < 0)
{
CORE_LOG_ERROR(m_logger, "Error finding stream in URL: " << m_url);
avformat_close_input(&m_ifmtctx);
m_ifmtctx = NULL;
return false;
}

//search for the first video stream
m_stream_index = -1;
for (unsigned int i = 0; i < m_ifmtctx->nb_streams && m_stream_index == -1; i++)
{
m_iccx = m_ifmtctx->streams[i]->codec;
if (m_iccx->codec_type == AVMEDIA_TYPE_VIDEO)
{
m_istream = m_ifmtctx->streams[i];
m_stream_index = i;
}
}

if (m_stream_index == -1)
{
CORE_LOG_ERROR(m_logger, "Could not find video stream in URL: " << m_url);
avformat_close_input(&m_ifmtctx);
m_ifmtctx = NULL;
return false;
}

return true;
}

bool RecordingStreamGrabber::prepareOutputStream()
{
if (m_ofmtctx)
{
CORE_LOG_DEBUG(m_logger, "Close outputfile: " << m_targetfile);
avformat_free_context(m_ofmtctx);
m_ofmtctx = NULL;
}

m_ofmt = av_guess_format(NULL, m_targetfile.c_str(), NULL);

m_ofmtctx = avformat_alloc_context();

m_ofmtctx->oformat = m_ofmt;

if (avio_open2(&m_ofmtctx->pb, m_targetfile.c_str(), AVIO_FLAG_WRITE, NULL, NULL) != 0)
{
avformat_free_context(m_ofmtctx);
m_ofmtctx = NULL;
CORE_LOG_ERROR(m_logger, "Error opening outputfile: " << m_targetfile);
return false;
}

m_ostream = avformat_new_stream(m_ofmtctx, NULL);

avcodec_copy_context(m_ostream->codec, m_iccx);

m_ostream->sample_aspect_ratio.num = m_iccx->sample_aspect_ratio.num;
m_ostream->sample_aspect_ratio.den = m_iccx->sample_aspect_ratio.den;

/* time base: 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
identically 1. */
m_ostream->time_base.num = m_iccx->time_base.num;
m_ostream->time_base.den = m_iccx->time_base.den;

avformat_write_header(m_ofmtctx, NULL);

#ifdef WIN32
sprintf_s(m_ofmtctx->filename, sizeof(m_ofmtctx->filename), "%s", m_targetfile.c_str());
#else
snprintf(m_ofmtctx->filename, sizeof(m_ofmtctx->filename), "%s", m_targetfile.c_str());
#endif
return true;
}

Логика записи

void RecordingStreamGrabber::run(RecordingStreamGrabber *_this)
{
AVPacket packet;
av_init_packet(&packet);
int i = 0;
bool startFrame = true;
bool keyFrame = false;
int64_t pts, dts;
_this->m_tailWritten = true;
while (_this->m_run)
{
if (av_read_frame(_this->m_ifmtctx, &packet) >= 0)
{
if ((packet.flags & AV_PKT_FLAG_KEY) == AV_PKT_FLAG_KEY)
{
keyFrame = true;
CORE_LOG_DEBUG(_this->m_logger, "Detected key frame: " << i << "");
}

if (_this->m_record)
{
if (packet.stream_index == _this->m_stream_index)
{
packet.stream_index = _this->m_ostream->id;

if (_this->m_tailWritten == false || keyFrame == true)
{
//#####################################
//timebase repair logic (my changes)
//#####################################
AVStream *in_stream;
AVStream *out_stream;

in_stream = _this->m_ifmtctx->streams[packet.stream_index];
out_stream = _this->m_ofmtctx->streams[packet.stream_index];

if (startFrame)
{
pts = packet.pts;
dts = packet.dts;
startFrame = false;
}
packet.pts -= pts;
packet.dts -= dts;

packet.pts = av_rescale_q_rnd(packet.pts, in_stream->time_base, out_stream->time_base, (AVRounding)((int)AV_ROUND_NEAR_INF | (int)AV_ROUND_PASS_MINMAX));
packet.dts = av_rescale_q_rnd(packet.dts, in_stream->time_base, out_stream->time_base, (AVRounding)((int)AV_ROUND_NEAR_INF | (int)AV_ROUND_PASS_MINMAX));

packet.duration = av_rescale_q(packet.duration, in_stream->time_base, out_stream->time_base);
//end of my changes

av_interleaved_write_frame(_this->m_ofmtctx, &packet);
_this->m_tailWritten = false;
}
}
}
else if (_this->m_ofmtctx)
{
if (_this->m_tailWritten == false)
{
av_write_trailer(_this->m_ofmtctx);
avio_close(_this->m_ofmtctx->pb);
}
avformat_free_context(_this->m_ofmtctx);
_this->m_tailWritten = true;
_this->m_ofmtctx = NULL;
startFrame = true;
}
i++;
keyFrame = false;
}
av_free_packet(&packet);
av_init_packet(&packet);
}
if (_this->m_record)
{
av_write_trailer(_this->m_ofmtctx);
avio_close(_this->m_ofmtctx->pb);
}
if (_this->m_ofmtctx)
{
avformat_free_context(_this->m_ofmtctx);
_this->m_ofmtctx = NULL;
}
_this->m_record = false;

avformat_close_input(&_this->m_ifmtctx);
_this->m_ifmtctx = NULL;
}

Другой вопрос
Как я могу проверить, использует ли мой проект устарел API (ответ @berak)?

1

Решение

Задача ещё не решена.

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]