replay: fix video decoding from files with audio streams (#35715)

* fix video decoding from files with audio streams

* use av_find_best_stream

* streamlined logic
pull/35724/merge
Dean Lee 2 days ago committed by GitHub
parent 3a2c4a855a
commit 97f6dc6e8c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 43
      tools/replay/framereader.cc
  2. 1
      tools/replay/framereader.h

@ -80,7 +80,13 @@ bool FrameReader::loadFromFile(CameraType type, const std::string &file, bool no
}
input_ctx->probesize = 10 * 1024 * 1024; // 10MB
decoder_ = decoder_manager.acquire(type, input_ctx->streams[0]->codecpar, !no_hw_decoder);
video_stream_idx_ = av_find_best_stream(input_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
if (video_stream_idx_ < 0) {
rError("No video stream found in file");
return false;
}
decoder_ = decoder_manager.acquire(type, input_ctx->streams[video_stream_idx_]->codecpar, !no_hw_decoder);
if (!decoder_) {
return false;
}
@ -90,7 +96,9 @@ bool FrameReader::loadFromFile(CameraType type, const std::string &file, bool no
AVPacket pkt;
packets_info.reserve(60 * 20); // 20fps, one minute
while (!(abort && *abort) && av_read_frame(input_ctx, &pkt) == 0) {
packets_info.emplace_back(PacketInfo{.flags = pkt.flags, .pos = pkt.pos});
if (pkt.stream_index == video_stream_idx_) {
packets_info.emplace_back(PacketInfo{.flags = pkt.flags, .pos = pkt.pos});
}
av_packet_unref(&pkt);
}
avio_seek(input_ctx->pb, 0, SEEK_SET);
@ -168,17 +176,17 @@ bool VideoDecoder::initHardwareDecoder(AVHWDeviceType hw_device_type) {
}
bool VideoDecoder::decode(FrameReader *reader, int idx, VisionBuf *buf) {
int from_idx = idx;
int current_idx = idx;
if (idx != reader->prev_idx + 1) {
// seeking to the nearest key frame
for (int i = idx; i >= 0; --i) {
if (reader->packets_info[i].flags & AV_PKT_FLAG_KEY) {
from_idx = i;
current_idx = i;
break;
}
}
auto pos = reader->packets_info[from_idx].pos;
auto pos = reader->packets_info[current_idx].pos;
int ret = avformat_seek_file(reader->input_ctx, 0, pos, pos, pos, AVSEEK_FLAG_BYTE);
if (ret < 0) {
rError("Failed to seek to byte position %lld: %d", pos, AVERROR(ret));
@ -188,18 +196,27 @@ bool VideoDecoder::decode(FrameReader *reader, int idx, VisionBuf *buf) {
}
reader->prev_idx = idx;
bool result = false;
AVPacket pkt;
for (int i = from_idx; i <= idx; ++i) {
if (av_read_frame(reader->input_ctx, &pkt) == 0) {
AVFrame *f = decodeFrame(&pkt);
if (f && i == idx) {
result = copyBuffer(f, buf);
}
while (av_read_frame(reader->input_ctx, &pkt) >= 0) {
// Skip non-video packets
if (pkt.stream_index != reader->video_stream_idx_) {
av_packet_unref(&pkt);
continue;
}
AVFrame *frame = decodeFrame(&pkt);
av_packet_unref(&pkt);
if (!frame) {
rError("Failed to decode frame at index %d", current_idx);
return false;
}
if (current_idx++ == idx) {
return copyBuffer(frame, buf);
}
}
return result;
rError("Failed to find frame at index %d", idx);
return false;
}
AVFrame *VideoDecoder::decodeFrame(AVPacket *pkt) {

@ -28,6 +28,7 @@ public:
VideoDecoder *decoder_ = nullptr;
AVFormatContext *input_ctx = nullptr;
int video_stream_idx_ = -1;
int prev_idx = -1;
struct PacketInfo {
int flags;

Loading…
Cancel
Save