Seek - Bug Fixes + Sample Update (#327)

* adds seek to videodecode and seek bug fixes

* fixes both frames & timestamp with prev_key_frame option

* switch to exact key frame and bug fix

* fix decoded_frame_number from seek

* fix out_frame_duration

* clean up + exact fram fix

[ROCm/rocdecode commit: 2d50d685f7]
Этот коммит содержится в:
Lakshmi Kumar
2024-05-01 14:03:27 -07:00
коммит произвёл GitHub
родитель 69ac148c4d
Коммит 97be0bb3ca
2 изменённых файлов: 81 добавлений и 31 удалений
+31 -28
Просмотреть файл
@@ -143,7 +143,6 @@ class VideoDemuxer {
int64_t TsFromTime(double ts_sec) {
// Convert integer timestamp representation to AV_TIME_BASE and switch to fixed_point
auto const ts_tbu = llround(ts_sec * AV_TIME_BASE);
// Rescale the timestamp to value represented in stream base units;
AVRational time_factor = {1, AV_TIME_BASE};
return av_rescale_q(ts_tbu, time_factor, av_fmt_input_ctx_->streams[av_stream_]->time_base);
@@ -183,6 +182,7 @@ class VideoDemuxer {
uint32_t bit_depth_ = 0;
uint32_t byte_per_pixel_ = 0;
uint32_t bit_rate_ = 0;
int64_t pkt_dts_ = 0; // used for Seek Exact frame
};
VideoDemuxer::~VideoDemuxer() {
@@ -237,28 +237,29 @@ bool VideoDemuxer::Demux(uint8_t **video, int *video_size, int64_t *pts) {
}
*video = packet_filtered_->data;
*video_size = packet_filtered_->size;
pkt_dts_ = packet_filtered_->dts;
if (pts)
*pts = (int64_t) (packet_filtered_->pts * default_time_scale_ * time_base_);
} else {
if (is_mpeg4_ && (frame_count_ == 0)) {
int ext_data_size = av_fmt_input_ctx_->streams[av_stream_]->codecpar->extradata_size;
if (ext_data_size > 0) {
data_with_header_ = (uint8_t *)av_malloc(ext_data_size + packet_->size - 3 * sizeof(uint8_t));
if (!data_with_header_) {
std::cerr << "ERROR: av_malloc failed!" << std::endl;
return false;
}
memcpy(data_with_header_, av_fmt_input_ctx_->streams[av_stream_]->codecpar->extradata, ext_data_size);
memcpy(data_with_header_ + ext_data_size, packet_->data + 3, packet_->size - 3 * sizeof(uint8_t));
*video = data_with_header_;
*video_size = ext_data_size + packet_->size - 3 * sizeof(uint8_t);
} else {
if (is_mpeg4_ && (frame_count_ == 0)) {
int ext_data_size = av_fmt_input_ctx_->streams[av_stream_]->codecpar->extradata_size;
if (ext_data_size > 0) {
data_with_header_ = (uint8_t *)av_malloc(ext_data_size + packet_->size - 3 * sizeof(uint8_t));
if (!data_with_header_) {
std::cerr << "ERROR: av_malloc failed!" << std::endl;
return false;
}
} else {
*video = packet_->data;
*video_size = packet_->size;
memcpy(data_with_header_, av_fmt_input_ctx_->streams[av_stream_]->codecpar->extradata, ext_data_size);
memcpy(data_with_header_ + ext_data_size, packet_->data + 3, packet_->size - 3 * sizeof(uint8_t));
*video = data_with_header_;
*video_size = ext_data_size + packet_->size - 3 * sizeof(uint8_t);
}
if (pts)
*pts = (int64_t)(packet_->pts * default_time_scale_ * time_base_);
} else {
*video = packet_->data;
*video_size = packet_->size;
}
if (pts)
*pts = (int64_t)(packet_->pts * default_time_scale_ * time_base_);
}
frame_count_++;
return true;
@@ -394,7 +395,7 @@ VideoDemuxer::VideoDemuxer(AVFormatContext *av_fmt_input_ctx) : av_fmt_input_ctx
}
}
bool VideoDemuxer::Seek(VideoSeekContext& seek_ctx, uint8_t** pp_video, int* video_size) {
bool VideoDemuxer::Seek(VideoSeekContext& seek_ctx, uint8_t** pp_video, int* video_size) {
/* !!! IMPORTANT !!!
* Across this function, packet decode timestamp (DTS) values are used to
* compare given timestamp against. This is done because DTS values shall
@@ -433,7 +434,7 @@ bool VideoDemuxer::Seek(VideoSeekContext& seek_ctx, uint8_t** pp_video, int* vid
}
if (ret < 0) {
throw std::runtime_error("ERROR: seeking for frame: ");
throw std::runtime_error("ERROR: seeking for frame");
}
};
@@ -453,10 +454,10 @@ bool VideoDemuxer::Seek(VideoSeekContext& seek_ctx, uint8_t** pp_video, int* vid
return -1;
}
if (pkt_data.dts == target_ts) {
if (pkt_dts_ == target_ts) {
return 0;
}
else if (pkt_data.dts > target_ts) {
else if (pkt_dts_ > target_ts) {
return 1;
}
else {
@@ -473,7 +474,7 @@ bool VideoDemuxer::Seek(VideoSeekContext& seek_ctx, uint8_t** pp_video, int* vid
int seek_done = 0;
do {
if (!Demux(pp_video, video_size)) {
if (!Demux(pp_video, video_size, &pkt_data.pts)) {
break;
}
seek_done = is_seek_done(pkt_data, seek_ctx);
@@ -485,7 +486,8 @@ bool VideoDemuxer::Seek(VideoSeekContext& seek_ctx, uint8_t** pp_video, int* vid
}
// Need to read more frames until we reach requested number;
else if (seek_done < 0) {
continue;
tmp_ctx.seek_frame_++;
seek_frame(tmp_ctx, AVSEEK_FLAG_ANY);
}
} while (seek_done != 0);
@@ -495,10 +497,11 @@ bool VideoDemuxer::Seek(VideoSeekContext& seek_ctx, uint8_t** pp_video, int* vid
// Seek for closest key frame in the past;
auto seek_for_prev_key_frame = [&](PacketData& pkt_data, VideoSeekContext& seek_ctx) {
seek_frame(seek_ctx.seek_crit_, AVSEEK_FLAG_BACKWARD);
Demux(pp_video, video_size);
seek_frame(seek_ctx, AVSEEK_FLAG_BACKWARD);
Demux(pp_video, video_size, &pkt_data.pts);
seek_ctx.num_frames_decoded_ = static_cast<uint64_t>(pkt_data.pts / 1000 * frame_rate_);
seek_ctx.out_frame_pts_ = pkt_data.pts;
seek_ctx.out_frame_duration_ = pkt_data.duration;
seek_ctx.out_frame_duration_ = static_cast<int64_t>(pkt_data.pts / 1000);
};
PacketData pktData;