develop/projects/rocdecode/utils/video_demuxer.h Source File

develop/projects/rocdecode/utils/video_demuxer.h Source File#

15 min read time

Applies to Linux

rocDecode: develop/projects/rocdecode/utils/video_demuxer.h Source File
video_demuxer.h
Go to the documentation of this file.
1 /*
2 Copyright (c) 2023 - 2026 Advanced Micro Devices, Inc. All rights reserved.
3 
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10 
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13 
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 THE SOFTWARE.
21 */
22 
23 #pragma once
24 
25 #include <iostream>
26 extern "C" {
27  #include <libavcodec/avcodec.h>
28  #include <libavformat/avformat.h>
29  #if USE_AVCODEC_GREATER_THAN_58_134
30  #include <libavcodec/bsf.h>
31  #endif
32 }
33 
34 #include <cstdint>
35 #include <cstring>
36 #include <ctime>
37 #include <time.h>
38 #include <unistd.h>
39 #include <sys/syscall.h>
40 #include <thread>
41 #include <sstream>
42 #include <iomanip>
43 #include "rocdecode/rocdecode.h"
44 
45 // Minimal critical logging for video_demuxer.h.
46 // Matches the format produced by the full logger in src/commons.h:
47 // [0, Critical] filename:line: timestamp_us us: [pid:X tid:Y hashid:0xZZZZZ] func(): message
48 #define DemuxCriticalLog(msg) \
49  do { \
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; \
62  } while (0)
63 
76 typedef enum SeekModeEnum {
77  SEEK_MODE_EXACT_FRAME = 0,
78  SEEK_MODE_PREV_KEY_FRAME = 1,
79  SEEK_MODE_NUM,
81 
86 typedef enum SeekCriteriaEnum {
87  SEEK_CRITERIA_FRAME_NUM = 0,
88  SEEK_CRITERIA_TIME_STAMP = 1,
89  SEEK_CRITERIA_NUM,
91 
92 struct PacketData {
93  int32_t key;
94  int64_t pts;
95  int64_t dts;
96  uint64_t pos;
97  uintptr_t bsl_data;
98  uint64_t bsl;
99  uint64_t duration;
100 };
101 
103 public:
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) {}
107 
108  VideoSeekContext(uint64_t frame_id)
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) {}
111 
112  VideoSeekContext& operator=(const VideoSeekContext& other) {
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_;
120  return *this;
121  }
122 
123  /* Will be set to false when not seeking, true otherwise;
124  */
125  bool use_seek_;
126 
127  /* Frame we want to get. Set by user.
128  * Shall be set to frame timestamp in case seek is done by time.
129  */
130  uint64_t seek_frame_;
131 
132  /* Mode in which we seek. */
133  SeekMode seek_mode_;
134 
135  /* Criteria by which we seek. */
136  SeekCriteria seek_crit_;
137 
138  /* PTS of frame found after seek. */
139  int64_t out_frame_pts_;
140 
141  /* Duration of frame found after seek. */
142  int64_t out_frame_duration_;
143 
144  /* Number of frames that were decoded during seek. */
145  uint64_t num_frames_decoded_;
146 
147  /* PTS of frame to seek as set by the user in seek_frame_. */
148  int64_t requested_frame_pts_;
149 };
150 
151 
152 // Video Demuxer Interface class
154  public:
156  public:
157  virtual ~StreamProvider() {}
158  virtual int GetData(uint8_t *buf, int buf_size) = 0;
159  virtual size_t GetBufferSize() = 0;
160  };
161  AVCodecID GetCodecID() { return av_video_codec_id_; };
162  VideoDemuxer(const char *input_file_path) : VideoDemuxer(CreateFmtContextUtil(input_file_path)) {}
163  VideoDemuxer(StreamProvider *stream_provider) : VideoDemuxer(CreateFmtContextUtil(stream_provider)) {av_io_ctx_ = av_fmt_input_ctx_->pb;}
164  ~VideoDemuxer() {
165  if (!av_fmt_input_ctx_) {
166  return;
167  }
168  if (packet_) {
169  av_packet_free(&packet_);
170  }
171  if (packet_filtered_) {
172  av_packet_free(&packet_filtered_);
173  }
174  if (av_bsf_ctx_) {
175  av_bsf_free(&av_bsf_ctx_);
176  }
177  avformat_close_input(&av_fmt_input_ctx_);
178  if (av_io_ctx_) {
179  av_freep(&av_io_ctx_->buffer);
180  av_freep(&av_io_ctx_);
181  }
182  if (data_with_header_) {
183  av_free(data_with_header_);
184  }
185  }
186  bool Demux(uint8_t **video, int *video_size, int64_t *pts = nullptr) {
187  if (!av_fmt_input_ctx_) {
188  return false;
189  }
190  *video_size = 0;
191  if (packet_->data) {
192  av_packet_unref(packet_);
193  }
194  int ret = 0;
195  while ((ret = av_read_frame(av_fmt_input_ctx_, packet_)) >= 0 && packet_->stream_index != av_stream_) {
196  av_packet_unref(packet_);
197  }
198  if (ret < 0) {
199  return false;
200  }
201  if (is_h264_ || is_hevc_) {
202  if (packet_filtered_->data) {
203  av_packet_unref(packet_filtered_);
204  }
205  if (av_bsf_send_packet(av_bsf_ctx_, packet_) != 0) {
206  DemuxCriticalLog("av_bsf_send_packet failed!");
207  return false;
208  }
209  if (av_bsf_receive_packet(av_bsf_ctx_, packet_filtered_) != 0) {
210  DemuxCriticalLog("av_bsf_receive_packet failed!");
211  return false;
212  }
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;
217  } else {
218  pkt_dts_ = packet_filtered_->pts;
219  }
220  if (pts) {
221  *pts = (int64_t) (packet_filtered_->pts * default_time_scale_ * time_base_);
222  pkt_duration_ = packet_filtered_->duration;
223  }
224  } else {
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!");
231  return false;
232  }
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!");
238  return false;
239  }
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_;
243  *video_size = total;
244  }
245  } else {
246  *video = packet_->data;
247  *video_size = packet_->size;
248  }
249  if (packet_->dts != AV_NOPTS_VALUE) {
250  pkt_dts_ = packet_->dts;
251  } else {
252  pkt_dts_ = packet_->pts;
253  }
254  if (pts) {
255  *pts = (int64_t)(packet_->pts * default_time_scale_ * time_base_);
256  pkt_duration_ = packet_->duration;
257  }
258  }
259  frame_count_++;
260  return true;
261  }
262  bool Seek(VideoSeekContext& seek_ctx, uint8_t** pp_video, int* video_size) {
263  /* !!! IMPORTANT !!!
264  * Across this function, packet decode timestamp (DTS) values are used to
265  * compare given timestamp against. This is done because DTS values shall
266  * monotonically increase during the course of decoding unlike PTS values
267  * which may be affected by frame reordering due to B frames.
268  */
269 
270  if (!is_seekable_) {
271  DemuxCriticalLog("Seek isn't supported for this input.");
272  return false;
273  }
274 
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.");
277  return false;
278  }
279  int64_t timestamp = 0;
280  // Seek for single frame;
281  auto seek_frame = [&](VideoSeekContext const& seek_ctx, int flags) {
282  bool seek_backward = true;
283  int ret = 0;
284 
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);
289  break;
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);
293  break;
294  default:
295  DemuxCriticalLog("Invalid seek criteria");
296  ret = -1;
297  }
298 
299  if (ret < 0) {
300  throw std::runtime_error("ERROR: seeking for frame");
301  }
302  };
303 
304  // Check if frame satisfies seek conditions;
305  auto is_seek_done = [&](PacketData& pkt_data, VideoSeekContext const& seek_ctx) {
306  int64_t target_ts = 0;
307 
308  switch (seek_ctx.seek_crit_) {
309  case SEEK_CRITERIA_FRAME_NUM:
310  target_ts = TsFromFrameNumber(seek_ctx.seek_frame_);
311  break;
312  case SEEK_CRITERIA_TIME_STAMP:
313  target_ts = TsFromTime(seek_ctx.seek_frame_);
314  break;
315  default:
316  DemuxCriticalLog("Invalid seek criteria");
317  return -1;
318  }
319 
320  if (pkt_dts_ == target_ts) {
321  return 0;
322  } else if (pkt_dts_ > target_ts) {
323  return 1;
324  } else {
325  return -1;
326  };
327  };
328 
329  /* This will seek for exact frame number;
330  * Note that decoder may not be able to decode such frame; */
331  auto seek_for_exact_frame = [&](PacketData& pkt_data, VideoSeekContext& seek_ctx) {
332  // Repetititive seek until seek condition is satisfied;
333  VideoSeekContext tmp_ctx(seek_ctx.seek_frame_);
334  seek_frame(tmp_ctx, AVSEEK_FLAG_ANY);
335 
336  int seek_done = 0;
337  do {
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");
340  }
341  seek_done = is_seek_done(pkt_data, seek_ctx);
342  //TODO: one last condition, check for a target too high than available for timestamp
343  if (seek_done > 0) { // We've gone too far and need to seek backwards;
344  if ((tmp_ctx.seek_frame_--) >= 0) {
345  seek_frame(tmp_ctx, AVSEEK_FLAG_ANY);
346  }
347  } else if (seek_done < 0) { // Need to read more frames until we reach requested number;
348  tmp_ctx.seek_frame_++;
349  seek_frame(tmp_ctx, AVSEEK_FLAG_ANY);
350  }
351  if (tmp_ctx.seek_frame_ == seek_ctx.seek_frame_) // if frame 'N' is too far and frame 'N-1' is too less from target. Avoids infinite loop between N & N-1
352  break;
353  } while (seek_done != 0);
354 
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_);
358  };
359 
360  // Seek for closest key frame in the past;
361  auto seek_for_prev_key_frame = [&](PacketData& pkt_data, VideoSeekContext& seek_ctx) {
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_);
368  };
369 
370  PacketData pktData;
371  pktData.bsl_data = size_t(*pp_video);
372  pktData.bsl = *video_size;
373 
374  switch (seek_ctx.seek_mode_) {
375  case SEEK_MODE_EXACT_FRAME:
376  seek_for_exact_frame(pktData, seek_ctx);
377  break;
378  case SEEK_MODE_PREV_KEY_FRAME:
379  seek_for_prev_key_frame(pktData, seek_ctx);
380  break;
381  default:
382  throw std::runtime_error("ERROR::Unsupported seek mode");
383  break;
384  }
385 
386  return true;
387  }
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) {
397  // Convert integer timestamp representation to AV_TIME_BASE and switch to fixed_point
398  auto const ts_tbu = llround(ts_sec * AV_TIME_BASE);
399  // Rescale the timestamp to value represented in stream base units;
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);
402  }
403 
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);
407  }
408 
409  private:
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!");
414  return;
415  }
416  packet_ = av_packet_alloc();
417  packet_filtered_ = av_packet_alloc();
418  if (!packet_ || !packet_filtered_) {
419  DemuxCriticalLog("av_packet_alloc failed!");
420  return;
421  }
422  if (avformat_find_stream_info(av_fmt_input_ctx_, nullptr) < 0) {
423  DemuxCriticalLog("avformat_find_stream_info failed!");
424  return;
425  }
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_);
431  return;
432  }
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);
442 
443  switch (chroma_format_) {
444  case AV_PIX_FMT_YUV420P10LE:
445  case AV_PIX_FMT_GRAY10LE:
446  bit_depth_ = 10;
447  chroma_height_ = (height_ + 1) >> 1;
448  byte_per_pixel_ = 2;
449  break;
450  case AV_PIX_FMT_YUV420P12LE:
451  bit_depth_ = 12;
452  chroma_height_ = (height_ + 1) >> 1;
453  byte_per_pixel_ = 2;
454  break;
455  case AV_PIX_FMT_YUV444P10LE:
456  bit_depth_ = 10;
457  chroma_height_ = height_ << 1;
458  byte_per_pixel_ = 2;
459  break;
460  case AV_PIX_FMT_YUV444P12LE:
461  bit_depth_ = 12;
462  chroma_height_ = height_ << 1;
463  byte_per_pixel_ = 2;
464  break;
465  case AV_PIX_FMT_YUV444P:
466  bit_depth_ = 8;
467  chroma_height_ = height_ << 1;
468  byte_per_pixel_ = 1;
469  break;
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:
475  bit_depth_ = 8;
476  chroma_height_ = (height_ + 1) >> 1;
477  byte_per_pixel_ = 1;
478  break;
479  default:
480  chroma_format_ = AV_PIX_FMT_YUV420P;
481  bit_depth_ = 8;
482  chroma_height_ = (height_ + 1) >> 1;
483  byte_per_pixel_ = 1;
484  }
485 
486  AVRational time_base = av_fmt_input_ctx_->streams[av_stream_]->time_base;
487  time_base_ = av_q2d(time_base);
488 
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"));
498 
499  // Check if the input file allow seek functionality.
500 #if USE_AVCODEC_GREATER_THAN_58_134
501  is_seekable_ = true; //for latest version of FFMPeg, read_seek and read_seek2 is not exposed in AVFormatContext
502 #else
503  is_seekable_ = av_fmt_input_ctx_->iformat->read_seek || av_fmt_input_ctx_->iformat->read_seek2;
504 #endif
505 
506  if (is_h264_) {
507  const AVBitStreamFilter *bsf = av_bsf_get_by_name("h264_mp4toannexb");
508  if (!bsf) {
509  DemuxCriticalLog("av_bsf_get_by_name() failed for h264_mp4toannexb");
510  av_packet_free(&packet_);
511  av_packet_free(&packet_filtered_);
512  return;
513  }
514  if (av_bsf_alloc(bsf, &av_bsf_ctx_) != 0) {
515  DemuxCriticalLog("av_bsf_alloc failed!");
516  return;
517  }
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!");
521  return;
522  }
523  }
524  if (is_hevc_) {
525  const AVBitStreamFilter *bsf = av_bsf_get_by_name("hevc_mp4toannexb");
526  if (!bsf) {
527  DemuxCriticalLog("av_bsf_get_by_name() failed for hevc_mp4toannexb");
528  av_packet_free(&packet_);
529  av_packet_free(&packet_filtered_);
530  return;
531  }
532  if (av_bsf_alloc(bsf, &av_bsf_ctx_) != 0 ) {
533  DemuxCriticalLog("av_bsf_alloc failed!");
534  return;
535  }
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!");
539  return;
540  }
541  }
542  }
543  AVFormatContext *CreateFmtContextUtil(StreamProvider *stream_provider) {
544  AVFormatContext *ctx = nullptr;
545  if (!(ctx = avformat_alloc_context())) {
546  DemuxCriticalLog("avformat_alloc_context failed!");
547  return nullptr;
548  }
549  uint8_t *avioc_buffer = nullptr;
550  int avioc_buffer_size = stream_provider->GetBufferSize();
551  avioc_buffer = (uint8_t *)av_malloc(avioc_buffer_size);
552  if (!avioc_buffer) {
553  DemuxCriticalLog("av_malloc failed!");
554  return nullptr;
555  }
556  av_io_ctx_ = avio_alloc_context(avioc_buffer, avioc_buffer_size,
557  0, stream_provider, &ReadPacket, nullptr, nullptr);
558  if (!av_io_ctx_) {
559  DemuxCriticalLog("avio_alloc_context failed!");
560  return nullptr;
561  }
562  ctx->pb = av_io_ctx_;
563 
564  if (avformat_open_input(&ctx, nullptr, nullptr, nullptr) != 0) {
565  DemuxCriticalLog("avformat_open_input failed!");
566  return nullptr;
567  }
568  return ctx;
569  }
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!");
575  return nullptr;
576  }
577  return ctx;
578  }
579  static int ReadPacket(void *data, uint8_t *buf, int buf_size) {
580  return ((StreamProvider *)data)->GetData(buf, buf_size);
581  }
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;
592  int av_stream_ = 0;
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;
600  uint32_t width_ = 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;
606  // used for Seek Exact frame
607  int64_t pkt_dts_ = 0;
608  int64_t pkt_duration_ = 0;
609 };
610 
611 static inline rocDecVideoCodec AVCodec2RocDecVideoCodec(AVCodecID av_codec) {
612  switch (av_codec) {
613  case AV_CODEC_ID_MPEG1VIDEO : return rocDecVideoCodec_MPEG1;
614  case AV_CODEC_ID_MPEG2VIDEO : return rocDecVideoCodec_MPEG2;
615  case AV_CODEC_ID_MPEG4 : return rocDecVideoCodec_MPEG4;
616  case AV_CODEC_ID_H264 : return rocDecVideoCodec_AVC;
617  case AV_CODEC_ID_HEVC : return rocDecVideoCodec_HEVC;
618  case AV_CODEC_ID_VP8 : return rocDecVideoCodec_VP8;
619  case AV_CODEC_ID_VP9 : return rocDecVideoCodec_VP9;
620  case AV_CODEC_ID_MJPEG : return rocDecVideoCodec_JPEG;
621  case AV_CODEC_ID_AV1 : return rocDecVideoCodec_AV1;
622  default : return rocDecVideoCodec_NumCodecs;
623  }
624 }
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.