27 #include <libavcodec/avcodec.h>
28 #include <libavformat/avformat.h>
29 #if USE_AVCODEC_GREATER_THAN_58_134
30 #include <libavcodec/bsf.h>
39 #include <sys/syscall.h>
48 #define DemuxCriticalLog(msg) \
50 struct timespec _ts_; \
51 clock_gettime(CLOCK_MONOTONIC, &_ts_); \
52 uint64_t _us_ = static_cast<uint64_t>(_ts_.tv_sec) * 1000000ULL + _ts_.tv_nsec / 1000ULL; \
53 const char *_f_ = strrchr(__FILE__, '/'); \
54 pid_t _tid_ = static_cast<pid_t>(syscall(SYS_gettid)); \
55 std::ostringstream _htid_oss_; \
56 _htid_oss_ << "0x" << std::hex << std::setw(5) << std::setfill('0') \
57 << (std::hash<std::thread::id>{}(std::this_thread::get_id()) & 0xFFFFF); \
58 std::cerr << "[0, Critical] " << (_f_ ? _f_ + 1 : __FILE__) \
59 << ":" << __LINE__ << ": " << _us_ << " us: [pid:" \
60 << getpid() << " tid:" << _tid_ << " hashid:" << _htid_oss_.str() << "] " \
61 << __func__ << "(): " << (msg) << std::endl; \
77 SEEK_MODE_EXACT_FRAME = 0,
78 SEEK_MODE_PREV_KEY_FRAME = 1,
87 SEEK_CRITERIA_FRAME_NUM = 0,
88 SEEK_CRITERIA_TIME_STAMP = 1,
105 : use_seek_(
false), seek_frame_(0), seek_mode_(SEEK_MODE_PREV_KEY_FRAME), seek_crit_(SEEK_CRITERIA_FRAME_NUM),
106 out_frame_pts_(0), out_frame_duration_(0), num_frames_decoded_(0U) {}
109 : use_seek_(
true), seek_frame_(frame_id), seek_mode_(SEEK_MODE_PREV_KEY_FRAME),
110 seek_crit_(SEEK_CRITERIA_FRAME_NUM), out_frame_pts_(0), out_frame_duration_(0), num_frames_decoded_(0U) {}
113 use_seek_ = other.use_seek_;
114 seek_frame_ = other.seek_frame_;
115 seek_mode_ = other.seek_mode_;
116 seek_crit_ = other.seek_crit_;
117 out_frame_pts_ = other.out_frame_pts_;
118 out_frame_duration_ = other.out_frame_duration_;
119 num_frames_decoded_ = other.num_frames_decoded_;
130 uint64_t seek_frame_;
139 int64_t out_frame_pts_;
142 int64_t out_frame_duration_;
145 uint64_t num_frames_decoded_;
148 int64_t requested_frame_pts_;
158 virtual int GetData(uint8_t *buf,
int buf_size) = 0;
159 virtual size_t GetBufferSize() = 0;
161 AVCodecID GetCodecID() {
return av_video_codec_id_; };
163 VideoDemuxer(StreamProvider *stream_provider) :
VideoDemuxer(CreateFmtContextUtil(stream_provider)) {av_io_ctx_ = av_fmt_input_ctx_->pb;}
165 if (!av_fmt_input_ctx_) {
169 av_packet_free(&packet_);
171 if (packet_filtered_) {
172 av_packet_free(&packet_filtered_);
175 av_bsf_free(&av_bsf_ctx_);
177 avformat_close_input(&av_fmt_input_ctx_);
179 av_freep(&av_io_ctx_->buffer);
180 av_freep(&av_io_ctx_);
182 if (data_with_header_) {
183 av_free(data_with_header_);
186 bool Demux(uint8_t **video,
int *video_size, int64_t *pts =
nullptr) {
187 if (!av_fmt_input_ctx_) {
192 av_packet_unref(packet_);
195 while ((ret = av_read_frame(av_fmt_input_ctx_, packet_)) >= 0 && packet_->stream_index != av_stream_) {
196 av_packet_unref(packet_);
201 if (is_h264_ || is_hevc_) {
202 if (packet_filtered_->data) {
203 av_packet_unref(packet_filtered_);
205 if (av_bsf_send_packet(av_bsf_ctx_, packet_) != 0) {
206 DemuxCriticalLog(
"av_bsf_send_packet failed!");
209 if (av_bsf_receive_packet(av_bsf_ctx_, packet_filtered_) != 0) {
210 DemuxCriticalLog(
"av_bsf_receive_packet failed!");
213 *video = packet_filtered_->data;
214 *video_size = packet_filtered_->size;
215 if (packet_filtered_->dts != AV_NOPTS_VALUE) {
216 pkt_dts_ = packet_filtered_->dts;
218 pkt_dts_ = packet_filtered_->pts;
221 *pts = (int64_t) (packet_filtered_->pts * default_time_scale_ * time_base_);
222 pkt_duration_ = packet_filtered_->duration;
225 if (is_mpeg4_ && (frame_count_ == 0)) {
226 int ext_data_size = av_fmt_input_ctx_->streams[av_stream_]->codecpar->extradata_size;
227 if (ext_data_size > 0) {
228 if (packet_->size < 3 ||
229 (
size_t)ext_data_size > SIZE_MAX - (size_t)(packet_->size - 3)) {
230 DemuxCriticalLog(
"malformed first MPEG-4 packet!");
233 size_t payload = (size_t)packet_->size - 3;
234 size_t total = (
size_t)ext_data_size + payload;
235 data_with_header_ = (uint8_t *)av_malloc(total);
236 if (!data_with_header_) {
237 DemuxCriticalLog(
"av_malloc failed!");
240 memcpy(data_with_header_, av_fmt_input_ctx_->streams[av_stream_]->codecpar->extradata, ext_data_size);
241 memcpy(data_with_header_ + ext_data_size, packet_->data + 3, payload);
242 *video = data_with_header_;
246 *video = packet_->data;
247 *video_size = packet_->size;
249 if (packet_->dts != AV_NOPTS_VALUE) {
250 pkt_dts_ = packet_->dts;
252 pkt_dts_ = packet_->pts;
255 *pts = (int64_t)(packet_->pts * default_time_scale_ * time_base_);
256 pkt_duration_ = packet_->duration;
262 bool Seek(
VideoSeekContext& seek_ctx, uint8_t** pp_video,
int* video_size) {
271 DemuxCriticalLog(
"Seek isn't supported for this input.");
275 if (IsVFR() && (SEEK_CRITERIA_FRAME_NUM == seek_ctx.seek_crit_)) {
276 DemuxCriticalLog(
"Can't seek by frame number in VFR sequences. Seek by timestamp instead.");
279 int64_t timestamp = 0;
282 bool seek_backward =
true;
285 switch (seek_ctx.seek_crit_) {
286 case SEEK_CRITERIA_FRAME_NUM:
287 timestamp = TsFromFrameNumber(seek_ctx.seek_frame_);
288 ret = av_seek_frame(av_fmt_input_ctx_, av_stream_, timestamp, seek_backward ? AVSEEK_FLAG_BACKWARD | flags : flags);
290 case SEEK_CRITERIA_TIME_STAMP:
291 timestamp = TsFromTime(seek_ctx.seek_frame_);
292 ret = av_seek_frame(av_fmt_input_ctx_, av_stream_, timestamp, seek_backward ? AVSEEK_FLAG_BACKWARD | flags : flags);
295 DemuxCriticalLog(
"Invalid seek criteria");
300 throw std::runtime_error(
"ERROR: seeking for frame");
306 int64_t target_ts = 0;
308 switch (seek_ctx.seek_crit_) {
309 case SEEK_CRITERIA_FRAME_NUM:
310 target_ts = TsFromFrameNumber(seek_ctx.seek_frame_);
312 case SEEK_CRITERIA_TIME_STAMP:
313 target_ts = TsFromTime(seek_ctx.seek_frame_);
316 DemuxCriticalLog(
"Invalid seek criteria");
320 if (pkt_dts_ == target_ts) {
322 }
else if (pkt_dts_ > target_ts) {
334 seek_frame(tmp_ctx, AVSEEK_FLAG_ANY);
338 if (!Demux(pp_video, video_size, &pkt_data.pts)) {
339 throw std::runtime_error(
"ERROR: Demux failed trying to seek for specified frame number/timestamp");
341 seek_done = is_seek_done(pkt_data, seek_ctx);
344 if ((tmp_ctx.seek_frame_--) >= 0) {
345 seek_frame(tmp_ctx, AVSEEK_FLAG_ANY);
347 }
else if (seek_done < 0) {
348 tmp_ctx.seek_frame_++;
349 seek_frame(tmp_ctx, AVSEEK_FLAG_ANY);
351 if (tmp_ctx.seek_frame_ == seek_ctx.seek_frame_)
353 }
while (seek_done != 0);
355 seek_ctx.out_frame_pts_ = pkt_data.pts;
356 seek_ctx.out_frame_duration_ = pkt_data.duration = pkt_duration_;
357 seek_ctx.requested_frame_pts_ = (int64_t) (timestamp * default_time_scale_ * time_base_);
362 seek_frame(seek_ctx, AVSEEK_FLAG_BACKWARD);
363 Demux(pp_video, video_size, &pkt_data.pts);
364 seek_ctx.num_frames_decoded_ =
static_cast<uint64_t
>(pkt_data.pts / 1000 * frame_rate_);
365 seek_ctx.out_frame_pts_ = pkt_data.pts;
366 seek_ctx.out_frame_duration_ = pkt_data.duration = pkt_duration_;
367 seek_ctx.requested_frame_pts_ = (int64_t) (timestamp * default_time_scale_ * time_base_);
371 pktData.bsl_data = size_t(*pp_video);
372 pktData.bsl = *video_size;
374 switch (seek_ctx.seek_mode_) {
375 case SEEK_MODE_EXACT_FRAME:
376 seek_for_exact_frame(pktData, seek_ctx);
378 case SEEK_MODE_PREV_KEY_FRAME:
379 seek_for_prev_key_frame(pktData, seek_ctx);
382 throw std::runtime_error(
"ERROR::Unsupported seek mode");
388 const uint32_t GetWidth()
const {
return width_;}
389 const uint32_t GetHeight()
const {
return height_;}
390 const uint32_t GetChromaHeight()
const {
return chroma_height_;}
391 const uint32_t GetBitDepth()
const {
return bit_depth_;}
392 const uint32_t GetBytePerPixel()
const {
return byte_per_pixel_;}
393 const uint32_t GetBitRate()
const {
return bit_rate_;}
394 const double GetFrameRate()
const {
return frame_rate_;};
395 bool IsVFR()
const {
return frame_rate_ != avg_frame_rate_; };
396 int64_t TsFromTime(
double ts_sec) {
398 auto const ts_tbu = llround(ts_sec * AV_TIME_BASE);
400 AVRational time_factor = {1, AV_TIME_BASE};
401 return av_rescale_q(ts_tbu, time_factor, av_fmt_input_ctx_->streams[av_stream_]->time_base);
404 int64_t TsFromFrameNumber(int64_t frame_num) {
405 auto const ts_sec =
static_cast<double>(frame_num) / frame_rate_;
406 return TsFromTime(ts_sec);
410 VideoDemuxer(AVFormatContext *av_fmt_input_ctx) : av_fmt_input_ctx_(av_fmt_input_ctx) {
411 av_log_set_level(AV_LOG_QUIET);
412 if (!av_fmt_input_ctx_) {
413 DemuxCriticalLog(
"av_fmt_input_ctx_ is not valid!");
416 packet_ = av_packet_alloc();
417 packet_filtered_ = av_packet_alloc();
418 if (!packet_ || !packet_filtered_) {
419 DemuxCriticalLog(
"av_packet_alloc failed!");
422 if (avformat_find_stream_info(av_fmt_input_ctx_,
nullptr) < 0) {
423 DemuxCriticalLog(
"avformat_find_stream_info failed!");
426 av_stream_ = av_find_best_stream(av_fmt_input_ctx_, AVMEDIA_TYPE_VIDEO, -1, -1,
nullptr, 0);
427 if (av_stream_ < 0) {
428 DemuxCriticalLog(
"av_find_best_stream failed!");
429 av_packet_free(&packet_);
430 av_packet_free(&packet_filtered_);
433 av_video_codec_id_ = av_fmt_input_ctx_->streams[av_stream_]->codecpar->codec_id;
434 width_ = av_fmt_input_ctx_->streams[av_stream_]->codecpar->width;
435 height_ = av_fmt_input_ctx_->streams[av_stream_]->codecpar->height;
436 chroma_format_ = (AVPixelFormat)av_fmt_input_ctx_->streams[av_stream_]->codecpar->format;
437 bit_rate_ = av_fmt_input_ctx_->streams[av_stream_]->codecpar->bit_rate;
438 if (av_fmt_input_ctx_->streams[av_stream_]->r_frame_rate.den != 0)
439 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);
440 if (av_fmt_input_ctx_->streams[av_stream_]->avg_frame_rate.den != 0)
441 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);
443 switch (chroma_format_) {
444 case AV_PIX_FMT_YUV420P10LE:
445 case AV_PIX_FMT_GRAY10LE:
447 chroma_height_ = (height_ + 1) >> 1;
450 case AV_PIX_FMT_YUV420P12LE:
452 chroma_height_ = (height_ + 1) >> 1;
455 case AV_PIX_FMT_YUV444P10LE:
457 chroma_height_ = height_ << 1;
460 case AV_PIX_FMT_YUV444P12LE:
462 chroma_height_ = height_ << 1;
465 case AV_PIX_FMT_YUV444P:
467 chroma_height_ = height_ << 1;
470 case AV_PIX_FMT_YUV420P:
471 case AV_PIX_FMT_YUVJ420P:
472 case AV_PIX_FMT_YUVJ422P:
473 case AV_PIX_FMT_YUVJ444P:
474 case AV_PIX_FMT_GRAY8:
476 chroma_height_ = (height_ + 1) >> 1;
480 chroma_format_ = AV_PIX_FMT_YUV420P;
482 chroma_height_ = (height_ + 1) >> 1;
486 AVRational time_base = av_fmt_input_ctx_->streams[av_stream_]->time_base;
487 time_base_ = av_q2d(time_base);
489 is_h264_ = av_video_codec_id_ == AV_CODEC_ID_H264 && (!strcmp(av_fmt_input_ctx_->iformat->long_name,
"QuickTime / MOV")
490 || !strcmp(av_fmt_input_ctx_->iformat->long_name,
"FLV (Flash Video)")
491 || !strcmp(av_fmt_input_ctx_->iformat->long_name,
"Matroska / WebM"));
492 is_hevc_ = av_video_codec_id_ == AV_CODEC_ID_HEVC && (!strcmp(av_fmt_input_ctx_->iformat->long_name,
"QuickTime / MOV")
493 || !strcmp(av_fmt_input_ctx_->iformat->long_name,
"FLV (Flash Video)")
494 || !strcmp(av_fmt_input_ctx_->iformat->long_name,
"Matroska / WebM"));
495 is_mpeg4_ = av_video_codec_id_ == AV_CODEC_ID_MPEG4 && (!strcmp(av_fmt_input_ctx_->iformat->long_name,
"QuickTime / MOV")
496 || !strcmp(av_fmt_input_ctx_->iformat->long_name,
"FLV (Flash Video)")
497 || !strcmp(av_fmt_input_ctx_->iformat->long_name,
"Matroska / WebM"));
500 #if USE_AVCODEC_GREATER_THAN_58_134
503 is_seekable_ = av_fmt_input_ctx_->iformat->read_seek || av_fmt_input_ctx_->iformat->read_seek2;
507 const AVBitStreamFilter *bsf = av_bsf_get_by_name(
"h264_mp4toannexb");
509 DemuxCriticalLog(
"av_bsf_get_by_name() failed for h264_mp4toannexb");
510 av_packet_free(&packet_);
511 av_packet_free(&packet_filtered_);
514 if (av_bsf_alloc(bsf, &av_bsf_ctx_) != 0) {
515 DemuxCriticalLog(
"av_bsf_alloc failed!");
518 avcodec_parameters_copy(av_bsf_ctx_->par_in, av_fmt_input_ctx_->streams[av_stream_]->codecpar);
519 if (av_bsf_init(av_bsf_ctx_) < 0) {
520 DemuxCriticalLog(
"av_bsf_init failed!");
525 const AVBitStreamFilter *bsf = av_bsf_get_by_name(
"hevc_mp4toannexb");
527 DemuxCriticalLog(
"av_bsf_get_by_name() failed for hevc_mp4toannexb");
528 av_packet_free(&packet_);
529 av_packet_free(&packet_filtered_);
532 if (av_bsf_alloc(bsf, &av_bsf_ctx_) != 0 ) {
533 DemuxCriticalLog(
"av_bsf_alloc failed!");
536 avcodec_parameters_copy(av_bsf_ctx_->par_in, av_fmt_input_ctx_->streams[av_stream_]->codecpar);
537 if (av_bsf_init(av_bsf_ctx_) < 0) {
538 DemuxCriticalLog(
"av_bsf_init failed!");
543 AVFormatContext *CreateFmtContextUtil(StreamProvider *stream_provider) {
544 AVFormatContext *ctx =
nullptr;
545 if (!(ctx = avformat_alloc_context())) {
546 DemuxCriticalLog(
"avformat_alloc_context failed!");
549 uint8_t *avioc_buffer =
nullptr;
550 int avioc_buffer_size = stream_provider->GetBufferSize();
551 avioc_buffer = (uint8_t *)av_malloc(avioc_buffer_size);
553 DemuxCriticalLog(
"av_malloc failed!");
556 av_io_ctx_ = avio_alloc_context(avioc_buffer, avioc_buffer_size,
557 0, stream_provider, &ReadPacket,
nullptr,
nullptr);
559 DemuxCriticalLog(
"avio_alloc_context failed!");
562 ctx->pb = av_io_ctx_;
564 if (avformat_open_input(&ctx,
nullptr,
nullptr,
nullptr) != 0) {
565 DemuxCriticalLog(
"avformat_open_input failed!");
570 AVFormatContext *CreateFmtContextUtil(
const char *input_file_path) {
571 avformat_network_init();
572 AVFormatContext *ctx =
nullptr;
573 if (avformat_open_input(&ctx, input_file_path,
nullptr,
nullptr) != 0 ) {
574 DemuxCriticalLog(
"avformat_open_input failed!");
579 static int ReadPacket(
void *data, uint8_t *buf,
int buf_size) {
580 return ((StreamProvider *)data)->GetData(buf, buf_size);
582 AVFormatContext *av_fmt_input_ctx_ =
nullptr;
583 AVIOContext *av_io_ctx_ =
nullptr;
584 AVPacket* packet_ =
nullptr;
585 AVPacket* packet_filtered_ =
nullptr;
586 AVBSFContext *av_bsf_ctx_ =
nullptr;
587 AVCodecID av_video_codec_id_;
588 AVPixelFormat chroma_format_;
589 double frame_rate_ = 0.0;
590 double avg_frame_rate_ = 0.0;
591 uint8_t *data_with_header_ =
nullptr;
593 bool is_h264_ =
false;
594 bool is_hevc_ =
false;
595 bool is_mpeg4_ =
false;
596 bool is_seekable_ =
false;
597 int64_t default_time_scale_ = 1000;
598 double time_base_ = 0.0;
599 uint32_t frame_count_ = 0;
601 uint32_t height_ = 0;
602 uint32_t chroma_height_ = 0;
603 uint32_t bit_depth_ = 0;
604 uint32_t byte_per_pixel_ = 0;
605 uint32_t bit_rate_ = 0;
607 int64_t pkt_dts_ = 0;
608 int64_t pkt_duration_ = 0;
611 static inline rocDecVideoCodec AVCodec2RocDecVideoCodec(AVCodecID av_codec) {
Definition: video_demuxer.h:155
Definition: video_demuxer.h:153
Definition: video_demuxer.h:102
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:92
SeekModeEnum
Enum for Seek mode.
Definition: video_demuxer.h:76
enum SeekModeEnum SeekMode
Enum for Seek mode.
SeekCriteriaEnum
Enum for Seek Criteria.
Definition: video_demuxer.h:86
enum SeekCriteriaEnum SeekCriteria
Enum for Seek Criteria.