27 #include <libavcodec/avcodec.h>
28 #include <libavformat/avformat.h>
29 #if USE_AVCODEC_GREATER_THAN_58_134
30 #include <libavcodec/bsf.h>
48 SEEK_MODE_EXACT_FRAME = 0,
49 SEEK_MODE_PREV_KEY_FRAME = 1,
58 SEEK_CRITERIA_FRAME_NUM = 0,
59 SEEK_CRITERIA_TIME_STAMP = 1,
76 : use_seek_(
false), seek_frame_(0), seek_mode_(SEEK_MODE_PREV_KEY_FRAME), seek_crit_(SEEK_CRITERIA_FRAME_NUM),
77 out_frame_pts_(0), out_frame_duration_(0), num_frames_decoded_(0U) {}
80 : use_seek_(
true), seek_frame_(frame_id), seek_mode_(SEEK_MODE_PREV_KEY_FRAME),
81 seek_crit_(SEEK_CRITERIA_FRAME_NUM), out_frame_pts_(0), out_frame_duration_(0), num_frames_decoded_(0U) {}
84 use_seek_ = other.use_seek_;
85 seek_frame_ = other.seek_frame_;
86 seek_mode_ = other.seek_mode_;
87 seek_crit_ = other.seek_crit_;
88 out_frame_pts_ = other.out_frame_pts_;
89 out_frame_duration_ = other.out_frame_duration_;
90 num_frames_decoded_ = other.num_frames_decoded_;
101 uint64_t seek_frame_;
110 int64_t out_frame_pts_;
113 int64_t out_frame_duration_;
116 uint64_t num_frames_decoded_;
127 virtual int GetData(uint8_t *buf,
int buf_size) = 0;
129 AVCodecID GetCodecID() {
return av_video_codec_id_; };
131 VideoDemuxer(StreamProvider *stream_provider) :
VideoDemuxer(CreateFmtContextUtil(stream_provider)) {av_io_ctx_ = av_fmt_input_ctx_->pb;}
133 bool Demux(uint8_t **video,
int *video_size, int64_t *pts =
nullptr);
135 const uint32_t GetWidth()
const {
return width_;}
136 const uint32_t GetHeight()
const {
return height_;}
137 const uint32_t GetChromaHeight()
const {
return chroma_height_;}
138 const uint32_t GetBitDepth()
const {
return bit_depth_;}
139 const uint32_t GetBytePerPixel()
const {
return byte_per_pixel_;}
140 const uint32_t GetBitRate()
const {
return bit_rate_;}
141 const double GetFrameRate()
const {
return frame_rate_;};
142 bool IsVFR()
const {
return frame_rate_ != avg_frame_rate_; };
143 int64_t TsFromTime(
double ts_sec) {
145 auto const ts_tbu = llround(ts_sec * AV_TIME_BASE);
148 AVRational time_factor = {1, AV_TIME_BASE};
149 return av_rescale_q(ts_tbu, time_factor, av_fmt_input_ctx_->streams[av_stream_]->time_base);
152 int64_t TsFromFrameNumber(int64_t frame_num) {
153 auto const ts_sec =
static_cast<double>(frame_num) / frame_rate_;
154 return TsFromTime(ts_sec);
159 AVFormatContext *CreateFmtContextUtil(StreamProvider *stream_provider);
160 AVFormatContext *CreateFmtContextUtil(
const char *input_file_path);
161 static int ReadPacket(
void *data, uint8_t *buf,
int buf_size);
162 AVFormatContext *av_fmt_input_ctx_ =
nullptr;
163 AVIOContext *av_io_ctx_ =
nullptr;
164 AVPacket* packet_ =
nullptr;
165 AVPacket* packet_filtered_ =
nullptr;
166 AVBSFContext *av_bsf_ctx_ =
nullptr;
167 AVCodecID av_video_codec_id_;
168 AVPixelFormat chroma_format_;
169 double frame_rate_ = 0.0;
170 double avg_frame_rate_ = 0.0;
171 uint8_t *data_with_header_ =
nullptr;
173 bool is_h264_ =
false;
174 bool is_hevc_ =
false;
175 bool is_mpeg4_ =
false;
176 bool is_seekable_ =
false;
177 int64_t default_time_scale_ = 1000;
178 double time_base_ = 0.0;
179 uint32_t frame_count_ = 0;
181 uint32_t height_ = 0;
182 uint32_t chroma_height_ = 0;
183 uint32_t bit_depth_ = 0;
184 uint32_t byte_per_pixel_ = 0;
185 uint32_t bit_rate_ = 0;
188 VideoDemuxer::~VideoDemuxer() {
189 if (!av_fmt_input_ctx_) {
193 av_packet_free(&packet_);
195 if (packet_filtered_) {
196 av_packet_free(&packet_filtered_);
199 av_bsf_free(&av_bsf_ctx_);
201 avformat_close_input(&av_fmt_input_ctx_);
203 av_freep(&av_io_ctx_->buffer);
204 av_freep(&av_io_ctx_);
206 if (data_with_header_) {
207 av_free(data_with_header_);
211 bool VideoDemuxer::Demux(uint8_t **video,
int *video_size, int64_t *pts) {
212 if (!av_fmt_input_ctx_) {
217 av_packet_unref(packet_);
220 while ((ret = av_read_frame(av_fmt_input_ctx_, packet_)) >= 0 && packet_->stream_index != av_stream_) {
221 av_packet_unref(packet_);
226 if (is_h264_ || is_hevc_) {
227 if (packet_filtered_->data) {
228 av_packet_unref(packet_filtered_);
230 if (av_bsf_send_packet(av_bsf_ctx_, packet_) != 0) {
231 std::cerr <<
"ERROR: av_bsf_send_packet failed!" << std::endl;
234 if (av_bsf_receive_packet(av_bsf_ctx_, packet_filtered_) != 0) {
235 std::cerr <<
"ERROR: av_bsf_receive_packet failed!" << std::endl;
238 *video = packet_filtered_->data;
239 *video_size = packet_filtered_->size;
241 *pts = (int64_t) (packet_filtered_->pts * default_time_scale_ * time_base_);
243 if (is_mpeg4_ && (frame_count_ == 0)) {
244 int ext_data_size = av_fmt_input_ctx_->streams[av_stream_]->codecpar->extradata_size;
245 if (ext_data_size > 0) {
246 data_with_header_ = (uint8_t *)av_malloc(ext_data_size + packet_->size - 3 *
sizeof(uint8_t));
247 if (!data_with_header_) {
248 std::cerr <<
"ERROR: av_malloc failed!" << std::endl;
251 memcpy(data_with_header_, av_fmt_input_ctx_->streams[av_stream_]->codecpar->extradata, ext_data_size);
252 memcpy(data_with_header_ + ext_data_size, packet_->data + 3, packet_->size - 3 *
sizeof(uint8_t));
253 *video = data_with_header_;
254 *video_size = ext_data_size + packet_->size - 3 *
sizeof(uint8_t);
257 *video = packet_->data;
258 *video_size = packet_->size;
261 *pts = (int64_t)(packet_->pts * default_time_scale_ * time_base_);
267 VideoDemuxer::VideoDemuxer(AVFormatContext *av_fmt_input_ctx) : av_fmt_input_ctx_(av_fmt_input_ctx) {
268 av_log_set_level(AV_LOG_QUIET);
269 if (!av_fmt_input_ctx_) {
270 std::cerr <<
"ERROR: av_fmt_input_ctx_ is not vaild!" << std::endl;
273 packet_ = av_packet_alloc();
274 packet_filtered_ = av_packet_alloc();
275 if (!packet_ || !packet_filtered_) {
276 std::cerr <<
"ERROR: av_packet_alloc failed!" << std::endl;
279 if (avformat_find_stream_info(av_fmt_input_ctx_,
nullptr) < 0) {
280 std::cerr <<
"ERROR: avformat_find_stream_info failed!" << std::endl;
283 av_stream_ = av_find_best_stream(av_fmt_input_ctx_, AVMEDIA_TYPE_VIDEO, -1, -1,
nullptr, 0);
284 if (av_stream_ < 0) {
285 std::cerr <<
"ERROR: av_find_best_stream failed!" << std::endl;
286 av_packet_free(&packet_);
287 av_packet_free(&packet_filtered_);
290 av_video_codec_id_ = av_fmt_input_ctx_->streams[av_stream_]->codecpar->codec_id;
291 width_ = av_fmt_input_ctx_->streams[av_stream_]->codecpar->width;
292 height_ = av_fmt_input_ctx_->streams[av_stream_]->codecpar->height;
293 chroma_format_ = (AVPixelFormat)av_fmt_input_ctx_->streams[av_stream_]->codecpar->format;
294 bit_rate_ = av_fmt_input_ctx_->streams[av_stream_]->codecpar->bit_rate;
295 if (av_fmt_input_ctx_->streams[av_stream_]->r_frame_rate.den != 0)
296 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);
297 if (av_fmt_input_ctx_->streams[av_stream_]->avg_frame_rate.den != 0)
298 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);
300 switch (chroma_format_) {
301 case AV_PIX_FMT_YUV420P10LE:
302 case AV_PIX_FMT_GRAY10LE:
304 chroma_height_ = (height_ + 1) >> 1;
307 case AV_PIX_FMT_YUV420P12LE:
309 chroma_height_ = (height_ + 1) >> 1;
312 case AV_PIX_FMT_YUV444P10LE:
314 chroma_height_ = height_ << 1;
317 case AV_PIX_FMT_YUV444P12LE:
319 chroma_height_ = height_ << 1;
322 case AV_PIX_FMT_YUV444P:
324 chroma_height_ = height_ << 1;
327 case AV_PIX_FMT_YUV420P:
328 case AV_PIX_FMT_YUVJ420P:
329 case AV_PIX_FMT_YUVJ422P:
330 case AV_PIX_FMT_YUVJ444P:
331 case AV_PIX_FMT_GRAY8:
333 chroma_height_ = (height_ + 1) >> 1;
337 chroma_format_ = AV_PIX_FMT_YUV420P;
339 chroma_height_ = (height_ + 1) >> 1;
343 AVRational time_base = av_fmt_input_ctx_->streams[av_stream_]->time_base;
344 time_base_ = av_q2d(time_base);
346 is_h264_ = av_video_codec_id_ == AV_CODEC_ID_H264 && (!strcmp(av_fmt_input_ctx_->iformat->long_name,
"QuickTime / MOV")
347 || !strcmp(av_fmt_input_ctx_->iformat->long_name,
"FLV (Flash Video)")
348 || !strcmp(av_fmt_input_ctx_->iformat->long_name,
"Matroska / WebM"));
349 is_hevc_ = av_video_codec_id_ == AV_CODEC_ID_HEVC && (!strcmp(av_fmt_input_ctx_->iformat->long_name,
"QuickTime / MOV")
350 || !strcmp(av_fmt_input_ctx_->iformat->long_name,
"FLV (Flash Video)")
351 || !strcmp(av_fmt_input_ctx_->iformat->long_name,
"Matroska / WebM"));
352 is_mpeg4_ = av_video_codec_id_ == AV_CODEC_ID_MPEG4 && (!strcmp(av_fmt_input_ctx_->iformat->long_name,
"QuickTime / MOV")
353 || !strcmp(av_fmt_input_ctx_->iformat->long_name,
"FLV (Flash Video)")
354 || !strcmp(av_fmt_input_ctx_->iformat->long_name,
"Matroska / WebM"));
357 is_seekable_ = av_fmt_input_ctx_->iformat->read_seek || av_fmt_input_ctx_->iformat->read_seek2;
360 const AVBitStreamFilter *bsf = av_bsf_get_by_name(
"h264_mp4toannexb");
362 std::cerr <<
"ERROR: av_bsf_get_by_name() failed" << std::endl;
363 av_packet_free(&packet_);
364 av_packet_free(&packet_filtered_);
367 if (av_bsf_alloc(bsf, &av_bsf_ctx_) != 0) {
368 std::cerr <<
"ERROR: av_bsf_alloc failed!" << std::endl;
371 avcodec_parameters_copy(av_bsf_ctx_->par_in, av_fmt_input_ctx_->streams[av_stream_]->codecpar);
372 if (av_bsf_init(av_bsf_ctx_) < 0) {
373 std::cerr <<
"ERROR: av_bsf_init failed!" << std::endl;
378 const AVBitStreamFilter *bsf = av_bsf_get_by_name(
"hevc_mp4toannexb");
380 std::cerr <<
"ERROR: av_bsf_get_by_name() failed" << std::endl;
381 av_packet_free(&packet_);
382 av_packet_free(&packet_filtered_);
385 if (av_bsf_alloc(bsf, &av_bsf_ctx_) != 0 ) {
386 std::cerr <<
"ERROR: av_bsf_alloc failed!" << std::endl;
389 avcodec_parameters_copy(av_bsf_ctx_->par_in, av_fmt_input_ctx_->streams[av_stream_]->codecpar);
390 if (av_bsf_init(av_bsf_ctx_) < 0) {
391 std::cerr <<
"ERROR: av_bsf_init failed!" << std::endl;
397 bool VideoDemuxer::Seek(
VideoSeekContext& seek_ctx, uint8_t** pp_video,
int* video_size) {
406 std::cerr <<
"ERROR: Seek isn't supported for this input." << std::endl;
410 if (IsVFR() && (SEEK_CRITERIA_FRAME_NUM == seek_ctx.seek_crit_)) {
411 std::cerr <<
"ERROR: Can't seek by frame number in VFR sequences. Seek by timestamp instead." << std::endl;
417 bool seek_backward =
true;
418 int64_t timestamp = 0;
421 switch (seek_ctx.seek_crit_) {
422 case SEEK_CRITERIA_FRAME_NUM:
423 timestamp = TsFromFrameNumber(seek_ctx.seek_frame_);
424 ret = av_seek_frame(av_fmt_input_ctx_, av_stream_, timestamp, seek_backward ? AVSEEK_FLAG_BACKWARD | flags : flags);
426 case SEEK_CRITERIA_TIME_STAMP:
427 timestamp = TsFromTime(seek_ctx.seek_frame_);
428 ret = av_seek_frame(av_fmt_input_ctx_, av_stream_, timestamp, seek_backward ? AVSEEK_FLAG_BACKWARD | flags : flags);
431 std::cerr <<
"ERROR: Invalid seek mode" << std::endl;
436 throw std::runtime_error(
"ERROR: seeking for frame: ");
442 int64_t target_ts = 0;
444 switch (seek_ctx.seek_crit_) {
445 case SEEK_CRITERIA_FRAME_NUM:
446 target_ts = TsFromFrameNumber(seek_ctx.seek_frame_);
448 case SEEK_CRITERIA_TIME_STAMP:
449 target_ts = TsFromTime(seek_ctx.seek_frame_);
452 std::cerr <<
"ERROR::Invalid seek criteria" << std::endl;
456 if (pkt_data.dts == target_ts) {
459 else if (pkt_data.dts > target_ts) {
472 seek_frame(tmp_ctx, AVSEEK_FLAG_ANY);
476 if (!Demux(pp_video, video_size)) {
479 seek_done = is_seek_done(pkt_data, seek_ctx);
483 tmp_ctx.seek_frame_--;
484 seek_frame(tmp_ctx, AVSEEK_FLAG_ANY);
487 else if (seek_done < 0) {
490 }
while (seek_done != 0);
492 seek_ctx.out_frame_pts_ = pkt_data.pts;
493 seek_ctx.out_frame_duration_ = pkt_data.duration;
498 seek_frame(seek_ctx.seek_crit_, AVSEEK_FLAG_BACKWARD);
499 Demux(pp_video, video_size);
500 seek_ctx.out_frame_pts_ = pkt_data.pts;
501 seek_ctx.out_frame_duration_ = pkt_data.duration;
505 pktData.bsl_data = size_t(*pp_video);
506 pktData.bsl = *video_size;
508 switch (seek_ctx.seek_mode_) {
509 case SEEK_MODE_EXACT_FRAME:
510 seek_for_exact_frame(pktData, seek_ctx);
512 case SEEK_MODE_PREV_KEY_FRAME:
513 seek_for_prev_key_frame(pktData, seek_ctx);
516 throw std::runtime_error(
"ERROR::Unsupported seek mode");
523 AVFormatContext *VideoDemuxer::CreateFmtContextUtil(StreamProvider *stream_provider) {
524 AVFormatContext *ctx =
nullptr;
525 if (!(ctx = avformat_alloc_context())) {
526 std::cerr <<
"ERROR: avformat_alloc_context failed" << std::endl;
529 uint8_t *avioc_buffer =
nullptr;
530 int avioc_buffer_size = 100 * 1024 * 1024;
531 avioc_buffer = (uint8_t *)av_malloc(avioc_buffer_size);
533 std::cerr <<
"ERROR: av_malloc failed!" << std::endl;
536 av_io_ctx_ = avio_alloc_context(avioc_buffer, avioc_buffer_size,
537 0, stream_provider, &ReadPacket,
nullptr,
nullptr);
539 std::cerr <<
"ERROR: avio_alloc_context failed!" << std::endl;
542 ctx->pb = av_io_ctx_;
544 if (avformat_open_input(&ctx,
nullptr,
nullptr,
nullptr) != 0) {
545 std::cerr <<
"ERROR: avformat_open_input failed!" << std::endl;
551 AVFormatContext *VideoDemuxer::CreateFmtContextUtil(
const char *input_file_path) {
552 avformat_network_init();
553 AVFormatContext *ctx =
nullptr;
554 if (avformat_open_input(&ctx, input_file_path,
nullptr,
nullptr) != 0 ) {
555 std::cerr <<
"ERROR: avformat_open_input failed!" << std::endl;
561 int VideoDemuxer::ReadPacket(
void *data, uint8_t *buf,
int buf_size) {
562 return ((StreamProvider *)data)->GetData(buf, buf_size);
565 static inline rocDecVideoCodec AVCodec2RocDecVideoCodec(AVCodecID av_codec) {
Definition: video_demuxer.h:124
Definition: video_demuxer.h:122
Definition: video_demuxer.h:73
The AMD rocDecode Library.
@ rocDecVideoCodec_AV1
Definition: rocdecode.h:84
@ rocDecVideoCodec_MPEG4
Definition: rocdecode.h:81
@ rocDecVideoCodec_HEVC
Definition: rocdecode.h:83
@ rocDecVideoCodec_MPEG1
Definition: rocdecode.h:79
@ rocDecVideoCodec_JPEG
Definition: rocdecode.h:87
@ rocDecVideoCodec_VP9
Definition: rocdecode.h:86
@ rocDecVideoCodec_AVC
Definition: rocdecode.h:82
@ rocDecVideoCodec_MPEG2
Definition: rocdecode.h:80
@ rocDecVideoCodec_VP8
Definition: rocdecode.h:85
@ rocDecVideoCodec_NumCodecs
Definition: rocdecode.h:88
Definition: video_demuxer.h:63
SeekModeEnum
Enum for Seek mode.
Definition: video_demuxer.h:47
enum SeekModeEnum SeekMode
Enum for Seek mode.
SeekCriteriaEnum
Enum for Seek Criteria.
Definition: video_demuxer.h:57
enum SeekCriteriaEnum SeekCriteria
Enum for Seek Criteria.