#ffmpeg
#ffmpeg
Вопрос:
vcodec_receive_frame
Функция не получила остальные кадры. Я проверил, что всего в видео было 132 кадра, и он получил только 125 кадров, потеряв 7 кадров в конце видео. Как я могу вернуть потерянные кадры обратно?
Но произошло что-то странное. Как вы можете видеть результат моей MyDecode::receiveFrame()
функции. Код внутри блока if (ret != 0){}
выполняется первым, но потерянные кадры находятся в конце видео. Так как же они могли появиться первыми? Что вызвало это?
MyDecode.cpp
AVFrame* MyDecode::receiveFrame()
{
mux.lock();
if (!codecCtx) {
mux.unlock();
return 0;
}
AVFrame* frame = av_frame_alloc();
int ret = avcodec_receive_frame(codecCtx, frame);
mux.unlock();
if (ret != 0)
{
static int lost_frames = 1;
std::cout << "Lost frames: " << lost_frames << std::endl;
lost_frames = 1;
av_frame_free(amp;frame);
return nullptr;
}
std::cout << "Received frames: " << received_frame_num << std::endl;
received_frame_num = 1;
return frame;
}
bool MyDecode::sendPacket(AVPacket* packet)
{
if (!packet || !packet->data || packet->size == 0)
return false;
mux.lock();
if (!codecCtx) {
mux.unlock();
return false;
}
int ret = avcodec_send_packet(codecCtx, packet);
mux.unlock();
av_packet_free(amp;packet);
if (ret != 0) {
return false;
}
return true;
}
Вывод на консоль
Total frames: 132
Lost frames: 1
Lost frames: 2
Lost frames: 3
Lost frames: 4
Lost frames: 5
Lost frames: 6
Lost frames: 7
Received frames: 1
Received frames: 2
Received frames: 3
................
Received frames: 125
Обновить:
MyDemux.cpp
AVPacket* MyDemux::readFrame()
{
mux.lock();
if (!formatCtx) {
std::cout << "formaetCtx is null" << std::endl;
mux.unlock();
return nullptr;
}
AVPacket* packet = av_packet_alloc();
if (!packet) {
std::cout << "packet is null" << std::endl;
mux.unlock();
return nullptr;
}
int ret = av_read_frame(formatCtx, packet);
if (ret != 0) {
while (true) {
av_read_frame(formatCtx, nullptr);
}
mux.unlock();
av_packet_free(amp;packet);
av_packet_unref(packet);
return nullptr;
}
media_type = packet->stream_index;
mux.unlock();
return packet;
}
main.cpp
while (true) {
AVPacket* pkt = demux.readFrame();
if (demux.get_media_type() == 0) {
AVFrame* frame = video_decode.receiveFrame();
videoWidget->paintFrame(frame);
}
else if (demux.get_media_type() == 1) {
}
if (!pkt) {
std::cout << "to break" << std::endl;
break;
}
}
Ответ №1:
Вы должны отправить нулевые pkts в декодер, чтобы удалить все ожидающие кадры.
Из avcodec.h
Ситуации с завершением потока. Это требует «промывки» (иначе говоря, слива) кодека, поскольку кодек может буферизировать несколько кадров или пакетов внутри для повышения производительности или по необходимости (рассмотрим B-кадры).
Это обрабатывается следующим образом:
— Вместо допустимых входных данных отправьте NULL функциям avcodec_send_packet() (декодирование) или avcodec_send_frame () (кодирование). Это приведет к переходу в режим слива.
— Вызовите avcodec_receive_frame() (декодирование) или avcodec_receive_packet() (кодирование) в цикле, пока не будет возвращен AVERROR_EOF. Функции не вернут AVERROR (EAGAIN), если только вы не забыли перейти в режим слива. — Прежде чем декодирование можно будет возобновить снова, кодек должен быть сброшен с помощью avcodec_flush_buffers().
Комментарии:
1. Я пытался. Но у меня нет идеи, как это сделать конкретно, например, где я должен разместить
avcodec_send_frame(codecCtx, NULL)
.2. Как только вы получите EOF от входных данных, пропустите эту проверку:
if (!packet || !packet->data || packet->size == 0)
и отправляйте NULL до тех пор, пока не получите никаких кадров.3.
int ret = avcodec_receive_frame(codecCtx, frame); if (ret == AVERROR_EOF) {}
вот так? не работает