27 #include <libavcodec/avcodec.h>
28 #include <libavformat/avformat.h>
29 #if USE_AVCODEC_GREATER_THAN_58_134 || USE_AVCODEC_GREATER_THAN_60_31
30 #include <libavcodec/bsf.h>
40 #include <sys/syscall.h>
54 #define DemuxCriticalLog(msg) \
56 struct timespec _ts_; \
57 clock_gettime(CLOCK_MONOTONIC, &_ts_); \
58 uint64_t _us_ = static_cast<uint64_t>(_ts_.tv_sec) * 1000000ULL + _ts_.tv_nsec / 1000ULL; \
59 const char *_f_ = strrchr(__FILE__, '/'); \
60 pid_t _tid_ = static_cast<pid_t>(syscall(SYS_gettid)); \
61 std::ostringstream _htid_oss_; \
62 _htid_oss_ << "0x" << std::hex << std::setw(5) << std::setfill('0') \
63 << (std::hash<std::thread::id>{}(std::this_thread::get_id()) & 0xFFFFF); \
64 std::cerr << "[0, Critical] " << (_f_ ? _f_ + 1 : __FILE__) \
65 << ":" << __LINE__ << ": " << _us_ << " us: [pid:" \
66 << getpid() << " tid:" << _tid_ << " hashid:" << _htid_oss_.str() << "] " \
67 << __func__ << "(): " << (msg) << std::endl; \
70 #define DemuxCriticalLog(msg) \
74 static const LARGE_INTEGER _freq_ = [] { LARGE_INTEGER _f_ = {}; QueryPerformanceFrequency(&_f_); return _f_; }(); \
75 LARGE_INTEGER _cnt_; QueryPerformanceCounter(&_cnt_); \
77 uint64_t _us_ = static_cast<uint64_t>(_cnt_.QuadPart / _freq_.QuadPart) * 1000000ULL \
78 + static_cast<uint64_t>(_cnt_.QuadPart % _freq_.QuadPart) * 1000000ULL / _freq_.QuadPart; \
79 const char *_f_ = strrchr(__FILE__, '\\'); \
80 if (!_f_) _f_ = strrchr(__FILE__, '/'); \
81 DWORD _tid_ = GetCurrentThreadId(); \
82 std::ostringstream _htid_oss_; \
83 _htid_oss_ << "0x" << std::hex << std::setw(5) << std::setfill('0') \
84 << (std::hash<std::thread::id>{}(std::this_thread::get_id()) & 0xFFFFF); \
85 std::cerr << "[0, Critical] " << (_f_ ? _f_ + 1 : __FILE__) \
86 << ":" << __LINE__ << ": " << _us_ << " us: [pid:" \
87 << _getpid() << " tid:" << _tid_ << " hashid:" << _htid_oss_.str() << "] " \
88 << __func__ << "(): " << (msg) << std::endl; \
105 SEEK_MODE_EXACT_FRAME = 0,
106 SEEK_MODE_PREV_KEY_FRAME = 1,
115 SEEK_CRITERIA_FRAME_NUM = 0,
116 SEEK_CRITERIA_TIME_STAMP = 1,
133 : use_seek_(
false), seek_frame_(0), seek_mode_(SEEK_MODE_PREV_KEY_FRAME), seek_crit_(SEEK_CRITERIA_FRAME_NUM),
134 out_frame_pts_(0), out_frame_duration_(0), num_frames_decoded_(0U) {}
137 : use_seek_(
true), seek_frame_(frame_id), seek_mode_(SEEK_MODE_PREV_KEY_FRAME),
138 seek_crit_(SEEK_CRITERIA_FRAME_NUM), out_frame_pts_(0), out_frame_duration_(0), num_frames_decoded_(0U) {}
141 use_seek_ = other.use_seek_;
142 seek_frame_ = other.seek_frame_;
143 seek_mode_ = other.seek_mode_;
144 seek_crit_ = other.seek_crit_;
145 out_frame_pts_ = other.out_frame_pts_;
146 out_frame_duration_ = other.out_frame_duration_;
147 num_frames_decoded_ = other.num_frames_decoded_;
158 uint64_t seek_frame_;
167 int64_t out_frame_pts_;
170 int64_t out_frame_duration_;
173 uint64_t num_frames_decoded_;
176 int64_t requested_frame_pts_;
200 virtual int GetData(uint8_t *buf,
int buf_size) = 0;
224 if (!av_fmt_input_ctx_) {
228 av_packet_free(&packet_);
230 if (packet_filtered_) {
231 av_packet_free(&packet_filtered_);
234 av_bsf_free(&av_bsf_ctx_);
236 avformat_close_input(&av_fmt_input_ctx_);
238 av_freep(&av_io_ctx_->buffer);
239 av_freep(&av_io_ctx_);
241 if (data_with_header_) {
242 av_free(data_with_header_);
253 bool Demux(uint8_t **video,
int *video_size, int64_t *pts =
nullptr) {
254 if (!av_fmt_input_ctx_) {
259 av_packet_unref(packet_);
262 while ((ret = av_read_frame(av_fmt_input_ctx_, packet_)) >= 0 && packet_->stream_index != av_stream_) {
263 av_packet_unref(packet_);
268 if (is_h264_ || is_hevc_) {
269 if (packet_filtered_->data) {
270 av_packet_unref(packet_filtered_);
272 if (av_bsf_send_packet(av_bsf_ctx_, packet_) != 0) {
273 DemuxCriticalLog(
"av_bsf_send_packet failed!");
276 if (av_bsf_receive_packet(av_bsf_ctx_, packet_filtered_) != 0) {
277 DemuxCriticalLog(
"av_bsf_receive_packet failed!");
280 *video = packet_filtered_->data;
281 *video_size = packet_filtered_->size;
282 if (packet_filtered_->dts != AV_NOPTS_VALUE) {
283 pkt_dts_ = packet_filtered_->dts;
285 pkt_dts_ = packet_filtered_->pts;
288 *pts = (int64_t) (packet_filtered_->pts * default_time_scale_ * time_base_);
289 pkt_duration_ = packet_filtered_->duration;
292 if (is_mpeg4_ && (frame_count_ == 0)) {
293 int ext_data_size = av_fmt_input_ctx_->streams[av_stream_]->codecpar->extradata_size;
294 if (ext_data_size > 0) {
295 if (packet_->size < 3 ||
296 (
size_t)ext_data_size > SIZE_MAX - (size_t)(packet_->size - 3)) {
297 DemuxCriticalLog(
"malformed first MPEG-4 packet!");
300 size_t payload = (size_t)packet_->size - 3;
301 size_t total = (
size_t)ext_data_size + payload;
302 data_with_header_ = (uint8_t *)av_malloc(total);
303 if (!data_with_header_) {
304 DemuxCriticalLog(
"av_malloc failed!");
307 memcpy(data_with_header_, av_fmt_input_ctx_->streams[av_stream_]->codecpar->extradata, ext_data_size);
308 memcpy(data_with_header_ + ext_data_size, packet_->data + 3, payload);
309 *video = data_with_header_;
310 *video_size =
static_cast<int>(total);
313 *video = packet_->data;
314 *video_size = packet_->size;
316 if (packet_->dts != AV_NOPTS_VALUE) {
317 pkt_dts_ = packet_->dts;
319 pkt_dts_ = packet_->pts;
322 *pts = (int64_t)(packet_->pts * default_time_scale_ * time_base_);
323 pkt_duration_ = packet_->duration;
347 DemuxCriticalLog(
"Seek isn't supported for this input.");
351 if (
IsVFR() && (SEEK_CRITERIA_FRAME_NUM == seek_ctx.seek_crit_)) {
352 DemuxCriticalLog(
"Can't seek by frame number in VFR sequences. Seek by timestamp instead.");
355 int64_t timestamp = 0;
358 bool seek_backward =
true;
361 switch (seek_ctx.seek_crit_) {
362 case SEEK_CRITERIA_FRAME_NUM:
364 ret = av_seek_frame(av_fmt_input_ctx_, av_stream_, timestamp, seek_backward ? AVSEEK_FLAG_BACKWARD | flags : flags);
366 case SEEK_CRITERIA_TIME_STAMP:
367 timestamp =
TsFromTime(
static_cast<double>(seek_ctx.seek_frame_));
368 ret = av_seek_frame(av_fmt_input_ctx_, av_stream_, timestamp, seek_backward ? AVSEEK_FLAG_BACKWARD | flags : flags);
371 DemuxCriticalLog(
"Invalid seek criteria");
376 throw std::runtime_error(
"ERROR: seeking for frame");
382 int64_t target_ts = 0;
384 switch (seek_ctx.seek_crit_) {
385 case SEEK_CRITERIA_FRAME_NUM:
388 case SEEK_CRITERIA_TIME_STAMP:
389 target_ts =
TsFromTime(
static_cast<double>(seek_ctx.seek_frame_));
392 DemuxCriticalLog(
"Invalid seek criteria");
396 if (pkt_dts_ == target_ts) {
398 }
else if (pkt_dts_ > target_ts) {
410 seek_frame(tmp_ctx, AVSEEK_FLAG_ANY);
414 if (!
Demux(pp_video, video_size, &pkt_data.pts)) {
415 throw std::runtime_error(
"ERROR: Demux failed trying to seek for specified frame number/timestamp");
417 seek_done = is_seek_done(pkt_data, seek_ctx);
420 if ((tmp_ctx.seek_frame_--) >= 0) {
421 seek_frame(tmp_ctx, AVSEEK_FLAG_ANY);
423 }
else if (seek_done < 0) {
424 tmp_ctx.seek_frame_++;
425 seek_frame(tmp_ctx, AVSEEK_FLAG_ANY);
427 if (tmp_ctx.seek_frame_ == seek_ctx.seek_frame_)
429 }
while (seek_done != 0);
431 seek_ctx.out_frame_pts_ = pkt_data.pts;
432 seek_ctx.out_frame_duration_ = pkt_data.duration = pkt_duration_;
433 seek_ctx.requested_frame_pts_ = (int64_t) (timestamp * default_time_scale_ * time_base_);
438 seek_frame(seek_ctx, AVSEEK_FLAG_BACKWARD);
439 Demux(pp_video, video_size, &pkt_data.pts);
440 seek_ctx.num_frames_decoded_ =
static_cast<uint64_t
>(pkt_data.pts / 1000 * frame_rate_);
441 seek_ctx.out_frame_pts_ = pkt_data.pts;
442 seek_ctx.out_frame_duration_ = pkt_data.duration = pkt_duration_;
443 seek_ctx.requested_frame_pts_ = (int64_t) (timestamp * default_time_scale_ * time_base_);
447 pktData.bsl_data = size_t(*pp_video);
448 pktData.bsl = *video_size;
450 switch (seek_ctx.seek_mode_) {
451 case SEEK_MODE_EXACT_FRAME:
452 seek_for_exact_frame(pktData, seek_ctx);
454 case SEEK_MODE_PREV_KEY_FRAME:
455 seek_for_prev_key_frame(pktData, seek_ctx);
458 throw std::runtime_error(
"ERROR::Unsupported seek mode");
479 bool IsVFR()
const {
return frame_rate_ != avg_frame_rate_; };
487 auto const ts_tbu = llround(ts_sec * AV_TIME_BASE);
489 AVRational time_factor = {1, AV_TIME_BASE};
490 return av_rescale_q(ts_tbu, time_factor, av_fmt_input_ctx_->streams[av_stream_]->time_base);
499 auto const ts_sec =
static_cast<double>(frame_num) / frame_rate_;
504 VideoDemuxer(AVFormatContext *av_fmt_input_ctx) : av_fmt_input_ctx_(av_fmt_input_ctx) {
505 av_log_set_level(AV_LOG_QUIET);
506 if (!av_fmt_input_ctx_) {
507 DemuxCriticalLog(
"av_fmt_input_ctx_ is not valid!");
510 packet_ = av_packet_alloc();
511 packet_filtered_ = av_packet_alloc();
512 if (!packet_ || !packet_filtered_) {
513 DemuxCriticalLog(
"av_packet_alloc failed!");
516 if (avformat_find_stream_info(av_fmt_input_ctx_,
nullptr) < 0) {
517 DemuxCriticalLog(
"avformat_find_stream_info failed!");
520 av_stream_ = av_find_best_stream(av_fmt_input_ctx_, AVMEDIA_TYPE_VIDEO, -1, -1,
nullptr, 0);
521 if (av_stream_ < 0) {
522 DemuxCriticalLog(
"av_find_best_stream failed!");
523 av_packet_free(&packet_);
524 av_packet_free(&packet_filtered_);
527 av_video_codec_id_ = av_fmt_input_ctx_->streams[av_stream_]->codecpar->codec_id;
528 width_ = av_fmt_input_ctx_->streams[av_stream_]->codecpar->width;
529 height_ = av_fmt_input_ctx_->streams[av_stream_]->codecpar->height;
530 chroma_format_ = (AVPixelFormat)av_fmt_input_ctx_->streams[av_stream_]->codecpar->format;
531 bit_rate_ =
static_cast<uint32_t
>(av_fmt_input_ctx_->streams[av_stream_]->codecpar->bit_rate);
532 if (av_fmt_input_ctx_->streams[av_stream_]->r_frame_rate.den != 0)
533 frame_rate_ =
static_cast<double>(av_fmt_input_ctx_->streams[av_stream_]->r_frame_rate.num) /
static_cast<double>(av_fmt_input_ctx_->streams[av_stream_]->r_frame_rate.den);
534 if (av_fmt_input_ctx_->streams[av_stream_]->avg_frame_rate.den != 0)
535 avg_frame_rate_ =
static_cast<double>(av_fmt_input_ctx_->streams[av_stream_]->avg_frame_rate.num) /
static_cast<double>(av_fmt_input_ctx_->streams[av_stream_]->avg_frame_rate.den);
537 switch (chroma_format_) {
538 case AV_PIX_FMT_YUV420P10LE:
539 case AV_PIX_FMT_GRAY10LE:
541 chroma_height_ = (height_ + 1) >> 1;
544 case AV_PIX_FMT_YUV420P12LE:
546 chroma_height_ = (height_ + 1) >> 1;
549 case AV_PIX_FMT_YUV444P10LE:
551 chroma_height_ = height_ << 1;
554 case AV_PIX_FMT_YUV444P12LE:
556 chroma_height_ = height_ << 1;
559 case AV_PIX_FMT_YUV444P:
561 chroma_height_ = height_ << 1;
564 case AV_PIX_FMT_YUV420P:
565 case AV_PIX_FMT_YUVJ420P:
566 case AV_PIX_FMT_YUVJ422P:
567 case AV_PIX_FMT_YUVJ444P:
568 case AV_PIX_FMT_GRAY8:
570 chroma_height_ = (height_ + 1) >> 1;
574 chroma_format_ = AV_PIX_FMT_YUV420P;
576 chroma_height_ = (height_ + 1) >> 1;
580 AVRational time_base = av_fmt_input_ctx_->streams[av_stream_]->time_base;
581 time_base_ = av_q2d(time_base);
583 is_h264_ = av_video_codec_id_ == AV_CODEC_ID_H264 && (!strcmp(av_fmt_input_ctx_->iformat->long_name,
"QuickTime / MOV")
584 || !strcmp(av_fmt_input_ctx_->iformat->long_name,
"FLV (Flash Video)")
585 || !strcmp(av_fmt_input_ctx_->iformat->long_name,
"Matroska / WebM"));
586 is_hevc_ = av_video_codec_id_ == AV_CODEC_ID_HEVC && (!strcmp(av_fmt_input_ctx_->iformat->long_name,
"QuickTime / MOV")
587 || !strcmp(av_fmt_input_ctx_->iformat->long_name,
"FLV (Flash Video)")
588 || !strcmp(av_fmt_input_ctx_->iformat->long_name,
"Matroska / WebM"));
589 is_mpeg4_ = av_video_codec_id_ == AV_CODEC_ID_MPEG4 && (!strcmp(av_fmt_input_ctx_->iformat->long_name,
"QuickTime / MOV")
590 || !strcmp(av_fmt_input_ctx_->iformat->long_name,
"FLV (Flash Video)")
591 || !strcmp(av_fmt_input_ctx_->iformat->long_name,
"Matroska / WebM"));
594 #if USE_AVCODEC_GREATER_THAN_58_134 || USE_AVCODEC_GREATER_THAN_60_31
597 is_seekable_ = av_fmt_input_ctx_->iformat->read_seek || av_fmt_input_ctx_->iformat->read_seek2;
601 const AVBitStreamFilter *bsf = av_bsf_get_by_name(
"h264_mp4toannexb");
603 DemuxCriticalLog(
"av_bsf_get_by_name() failed for h264_mp4toannexb");
604 av_packet_free(&packet_);
605 av_packet_free(&packet_filtered_);
608 if (av_bsf_alloc(bsf, &av_bsf_ctx_) != 0) {
609 DemuxCriticalLog(
"av_bsf_alloc failed!");
612 avcodec_parameters_copy(av_bsf_ctx_->par_in, av_fmt_input_ctx_->streams[av_stream_]->codecpar);
613 if (av_bsf_init(av_bsf_ctx_) < 0) {
614 DemuxCriticalLog(
"av_bsf_init failed!");
619 const AVBitStreamFilter *bsf = av_bsf_get_by_name(
"hevc_mp4toannexb");
621 DemuxCriticalLog(
"av_bsf_get_by_name() failed for hevc_mp4toannexb");
622 av_packet_free(&packet_);
623 av_packet_free(&packet_filtered_);
626 if (av_bsf_alloc(bsf, &av_bsf_ctx_) != 0 ) {
627 DemuxCriticalLog(
"av_bsf_alloc failed!");
630 avcodec_parameters_copy(av_bsf_ctx_->par_in, av_fmt_input_ctx_->streams[av_stream_]->codecpar);
631 if (av_bsf_init(av_bsf_ctx_) < 0) {
632 DemuxCriticalLog(
"av_bsf_init failed!");
637 AVFormatContext *CreateFmtContextUtil(StreamProvider *stream_provider) {
638 AVFormatContext *ctx =
nullptr;
639 if (!(ctx = avformat_alloc_context())) {
640 DemuxCriticalLog(
"avformat_alloc_context failed!");
643 uint8_t *avioc_buffer =
nullptr;
644 int avioc_buffer_size =
static_cast<int>(stream_provider->GetBufferSize());
645 avioc_buffer = (uint8_t *)av_malloc(avioc_buffer_size);
647 DemuxCriticalLog(
"av_malloc failed!");
650 av_io_ctx_ = avio_alloc_context(avioc_buffer, avioc_buffer_size,
651 0, stream_provider, &ReadPacket,
nullptr,
nullptr);
653 DemuxCriticalLog(
"avio_alloc_context failed!");
656 ctx->pb = av_io_ctx_;
658 if (avformat_open_input(&ctx,
nullptr,
nullptr,
nullptr) != 0) {
659 DemuxCriticalLog(
"avformat_open_input failed!");
664 AVFormatContext *CreateFmtContextUtil(
const char *input_file_path) {
665 avformat_network_init();
666 AVFormatContext *ctx =
nullptr;
667 if (avformat_open_input(&ctx, input_file_path,
nullptr,
nullptr) != 0 ) {
668 DemuxCriticalLog(
"avformat_open_input failed!");
673 static int ReadPacket(
void *data, uint8_t *buf,
int buf_size) {
674 return ((StreamProvider *)data)->GetData(buf, buf_size);
676 AVFormatContext *av_fmt_input_ctx_ =
nullptr;
677 AVIOContext *av_io_ctx_ =
nullptr;
678 AVPacket* packet_ =
nullptr;
679 AVPacket* packet_filtered_ =
nullptr;
680 AVBSFContext *av_bsf_ctx_ =
nullptr;
681 AVCodecID av_video_codec_id_;
682 AVPixelFormat chroma_format_;
683 double frame_rate_ = 0.0;
684 double avg_frame_rate_ = 0.0;
685 uint8_t *data_with_header_ =
nullptr;
687 bool is_h264_ =
false;
688 bool is_hevc_ =
false;
689 bool is_mpeg4_ =
false;
690 bool is_seekable_ =
false;
691 int64_t default_time_scale_ = 1000;
692 double time_base_ = 0.0;
693 uint32_t frame_count_ = 0;
695 uint32_t height_ = 0;
696 uint32_t chroma_height_ = 0;
697 uint32_t bit_depth_ = 0;
698 uint32_t byte_per_pixel_ = 0;
699 uint32_t bit_rate_ = 0;
701 int64_t pkt_dts_ = 0;
702 int64_t pkt_duration_ = 0;
705 static inline rocDecVideoCodec AVCodec2RocDecVideoCodec(AVCodecID av_codec) {
Abstract interface that feeds a custom stream of bytes to the demuxer.
Definition: video_demuxer.h:193
virtual size_t GetBufferSize()=0
Returns the preferred buffer size to use for GetData reads.
virtual int GetData(uint8_t *buf, int buf_size)=0
Reads up to buf_size bytes of stream data into buf.
Demultiplexes a video stream into elementary packets that are passed to the rocDecode parser.
Definition: video_demuxer.h:185
const uint32_t GetHeight() const
Returns the height, in pixels, of the demultiplexed video stream.
Definition: video_demuxer.h:467
const uint32_t GetWidth() const
Returns the width, in pixels, of the demultiplexed video stream.
Definition: video_demuxer.h:465
const uint32_t GetBytePerPixel() const
Returns the number of bytes per pixel for the stream's chroma format.
Definition: video_demuxer.h:473
AVCodecID GetCodecID()
Returns the FFmpeg codec ID of the demultiplexed video stream.
Definition: video_demuxer.h:209
~VideoDemuxer()
Destroys the demuxer and releases the underlying FFmpeg resources.
Definition: video_demuxer.h:223
int64_t TsFromFrameNumber(int64_t frame_num)
Converts a frame number to the stream's internal time base units, using the stream's frame rate.
Definition: video_demuxer.h:498
const uint32_t GetBitDepth() const
Returns the bit depth of the demultiplexed video stream.
Definition: video_demuxer.h:471
const uint32_t GetChromaHeight() const
Returns the chroma plane height, in pixels, for the stream's chroma format.
Definition: video_demuxer.h:469
const double GetFrameRate() const
Returns the real (base) frame rate of the demultiplexed video stream.
Definition: video_demuxer.h:477
VideoDemuxer(const char *input_file_path)
Constructs a demuxer that reads the video stream from a file path.
Definition: video_demuxer.h:214
VideoDemuxer(StreamProvider *stream_provider)
Constructs a demuxer that reads the video stream from a custom StreamProvider.
Definition: video_demuxer.h:219
bool IsVFR() const
Returns true if the stream is variable frame rate (its real and average frame rates differ).
Definition: video_demuxer.h:479
int64_t TsFromTime(double ts_sec)
Converts a timestamp in seconds to the stream's internal time base units.
Definition: video_demuxer.h:485
const uint32_t GetBitRate() const
Returns the bit rate, in bits per second, reported by the input stream.
Definition: video_demuxer.h:475
bool Seek(VideoSeekContext &seek_ctx, uint8_t **pp_video, int *video_size)
Seeks to a frame identified by seek_ctx and demuxes it, instead of demuxing sequentially.
Definition: video_demuxer.h:338
bool Demux(uint8_t **video, int *video_size, int64_t *pts=nullptr)
Extracts the next elementary video packet from the stream, starting at the beginning.
Definition: video_demuxer.h:253
Definition: video_demuxer.h:130
The AMD rocDecode Library.
@ rocDecVideoCodec_AV1
Definition: rocdecode.h:83
@ rocDecVideoCodec_MPEG4
Definition: rocdecode.h:80
@ rocDecVideoCodec_HEVC
Definition: rocdecode.h:82
@ rocDecVideoCodec_MPEG1
Definition: rocdecode.h:78
@ rocDecVideoCodec_JPEG
Definition: rocdecode.h:86
@ rocDecVideoCodec_VP9
Definition: rocdecode.h:85
@ rocDecVideoCodec_AVC
Definition: rocdecode.h:81
@ rocDecVideoCodec_MPEG2
Definition: rocdecode.h:79
@ rocDecVideoCodec_VP8
Definition: rocdecode.h:84
@ rocDecVideoCodec_NumCodecs
Definition: rocdecode.h:87
Definition: video_demuxer.h:120
SeekModeEnum
Enum for Seek mode.
Definition: video_demuxer.h:104
enum SeekModeEnum SeekMode
Enum for Seek mode.
SeekCriteriaEnum
Enum for Seek Criteria.
Definition: video_demuxer.h:114
enum SeekCriteriaEnum SeekCriteria
Enum for Seek Criteria.