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

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

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 <cstring>
35 #include <ctime>
36 #include <time.h>
37 #include <unistd.h>
38 #include <sys/syscall.h>
39 #include <thread>
40 #include <sstream>
41 #include <iomanip>
42 #include "rocdecode/rocdecode.h"
43 
44 // Minimal critical logging for video_demuxer.h.
45 // Matches the format produced by the full logger in src/commons.h:
46 // [0, Critical] filename:line: timestamp_us us: [pid:X tid:Y hashid:0xZZZZZ] func(): message
47 #define DemuxCriticalLog(msg) \
48  do { \
49  struct timespec _ts_; \
50  clock_gettime(CLOCK_MONOTONIC, &_ts_); \
51  uint64_t _us_ = static_cast<uint64_t>(_ts_.tv_sec) * 1000000ULL + _ts_.tv_nsec / 1000ULL; \
52  const char *_f_ = strrchr(__FILE__, '/'); \
53  pid_t _tid_ = static_cast<pid_t>(syscall(SYS_gettid)); \
54  std::ostringstream _htid_oss_; \
55  _htid_oss_ << "0x" << std::hex << std::setw(5) << std::setfill('0') \
56  << (std::hash<std::thread::id>{}(std::this_thread::get_id()) & 0xFFFFF); \
57  std::cerr << "[0, Critical] " << (_f_ ? _f_ + 1 : __FILE__) \
58  << ":" << __LINE__ << ": " << _us_ << " us: [pid:" \
59  << getpid() << " tid:" << _tid_ << " hashid:" << _htid_oss_.str() << "] " \
60  << __func__ << "(): " << (msg) << std::endl; \
61  } while (0)
62 
75 typedef enum SeekModeEnum {
76  SEEK_MODE_EXACT_FRAME = 0,
77  SEEK_MODE_PREV_KEY_FRAME = 1,
78  SEEK_MODE_NUM,
80 
85 typedef enum SeekCriteriaEnum {
86  SEEK_CRITERIA_FRAME_NUM = 0,
87  SEEK_CRITERIA_TIME_STAMP = 1,
88  SEEK_CRITERIA_NUM,
90 
91 struct PacketData {
92  int32_t key;
93  int64_t pts;
94  int64_t dts;
95  uint64_t pos;
96  uintptr_t bsl_data;
97  uint64_t bsl;
98  uint64_t duration;
99 };
100 
102 public:
104  : use_seek_(false), seek_frame_(0), seek_mode_(SEEK_MODE_PREV_KEY_FRAME), seek_crit_(SEEK_CRITERIA_FRAME_NUM),
105  out_frame_pts_(0), out_frame_duration_(0), num_frames_decoded_(0U) {}
106 
107  VideoSeekContext(uint64_t frame_id)
108  : use_seek_(true), seek_frame_(frame_id), seek_mode_(SEEK_MODE_PREV_KEY_FRAME),
109  seek_crit_(SEEK_CRITERIA_FRAME_NUM), out_frame_pts_(0), out_frame_duration_(0), num_frames_decoded_(0U) {}
110 
111  VideoSeekContext& operator=(const VideoSeekContext& other) {
112  use_seek_ = other.use_seek_;
113  seek_frame_ = other.seek_frame_;
114  seek_mode_ = other.seek_mode_;
115  seek_crit_ = other.seek_crit_;
116  out_frame_pts_ = other.out_frame_pts_;
117  out_frame_duration_ = other.out_frame_duration_;
118  num_frames_decoded_ = other.num_frames_decoded_;
119  return *this;
120  }
121 
122  /* Will be set to false when not seeking, true otherwise;
123  */
124  bool use_seek_;
125 
126  /* Frame we want to get. Set by user.
127  * Shall be set to frame timestamp in case seek is done by time.
128  */
129  uint64_t seek_frame_;
130 
131  /* Mode in which we seek. */
132  SeekMode seek_mode_;
133 
134  /* Criteria by which we seek. */
135  SeekCriteria seek_crit_;
136 
137  /* PTS of frame found after seek. */
138  int64_t out_frame_pts_;
139 
140  /* Duration of frame found after seek. */
141  int64_t out_frame_duration_;
142 
143  /* Number of frames that were decoded during seek. */
144  uint64_t num_frames_decoded_;
145 
146  /* PTS of frame to seek as set by the user in seek_frame_. */
147  int64_t requested_frame_pts_;
148 };
149 
150 
151 // Video Demuxer Interface class
153  public:
155  public:
156  virtual ~StreamProvider() {}
157  virtual int GetData(uint8_t *buf, int buf_size) = 0;
158  virtual size_t GetBufferSize() = 0;
159  };
160  AVCodecID GetCodecID() { return av_video_codec_id_; };
161  VideoDemuxer(const char *input_file_path) : VideoDemuxer(CreateFmtContextUtil(input_file_path)) {}
162  VideoDemuxer(StreamProvider *stream_provider) : VideoDemuxer(CreateFmtContextUtil(stream_provider)) {av_io_ctx_ = av_fmt_input_ctx_->pb;}
163  ~VideoDemuxer() {
164  if (!av_fmt_input_ctx_) {
165  return;
166  }
167  if (packet_) {
168  av_packet_free(&packet_);
169  }
170  if (packet_filtered_) {
171  av_packet_free(&packet_filtered_);
172  }
173  if (av_bsf_ctx_) {
174  av_bsf_free(&av_bsf_ctx_);
175  }
176  avformat_close_input(&av_fmt_input_ctx_);
177  if (av_io_ctx_) {
178  av_freep(&av_io_ctx_->buffer);
179  av_freep(&av_io_ctx_);
180  }
181  if (data_with_header_) {
182  av_free(data_with_header_);
183  }
184  }
185  bool Demux(uint8_t **video, int *video_size, int64_t *pts = nullptr) {
186  if (!av_fmt_input_ctx_) {
187  return false;
188  }
189  *video_size = 0;
190  if (packet_->data) {
191  av_packet_unref(packet_);
192  }
193  int ret = 0;
194  while ((ret = av_read_frame(av_fmt_input_ctx_, packet_)) >= 0 && packet_->stream_index != av_stream_) {
195  av_packet_unref(packet_);
196  }
197  if (ret < 0) {
198  return false;
199  }
200  if (is_h264_ || is_hevc_) {
201  if (packet_filtered_->data) {
202  av_packet_unref(packet_filtered_);
203  }
204  if (av_bsf_send_packet(av_bsf_ctx_, packet_) != 0) {
205  DemuxCriticalLog("av_bsf_send_packet failed!");
206  return false;
207  }
208  if (av_bsf_receive_packet(av_bsf_ctx_, packet_filtered_) != 0) {
209  DemuxCriticalLog("av_bsf_receive_packet failed!");
210  return false;
211  }
212  *video = packet_filtered_->data;
213  *video_size = packet_filtered_->size;
214  if (packet_filtered_->dts != AV_NOPTS_VALUE) {
215  pkt_dts_ = packet_filtered_->dts;
216  } else {
217  pkt_dts_ = packet_filtered_->pts;
218  }
219  if (pts) {
220  *pts = (int64_t) (packet_filtered_->pts * default_time_scale_ * time_base_);
221  pkt_duration_ = packet_filtered_->duration;
222  }
223  } else {
224  if (is_mpeg4_ && (frame_count_ == 0)) {
225  int ext_data_size = av_fmt_input_ctx_->streams[av_stream_]->codecpar->extradata_size;
226  if (ext_data_size > 0) {
227  data_with_header_ = (uint8_t *)av_malloc(ext_data_size + packet_->size - 3 * sizeof(uint8_t));
228  if (!data_with_header_) {
229  DemuxCriticalLog("av_malloc failed!");
230  return false;
231  }
232  memcpy(data_with_header_, av_fmt_input_ctx_->streams[av_stream_]->codecpar->extradata, ext_data_size);
233  memcpy(data_with_header_ + ext_data_size, packet_->data + 3, packet_->size - 3 * sizeof(uint8_t));
234  *video = data_with_header_;
235  *video_size = ext_data_size + packet_->size - 3 * sizeof(uint8_t);
236  }
237  } else {
238  *video = packet_->data;
239  *video_size = packet_->size;
240  }
241  if (packet_->dts != AV_NOPTS_VALUE) {
242  pkt_dts_ = packet_->dts;
243  } else {
244  pkt_dts_ = packet_->pts;
245  }
246  if (pts) {
247  *pts = (int64_t)(packet_->pts * default_time_scale_ * time_base_);
248  pkt_duration_ = packet_->duration;
249  }
250  }
251  frame_count_++;
252  return true;
253  }
254  bool Seek(VideoSeekContext& seek_ctx, uint8_t** pp_video, int* video_size) {
255  /* !!! IMPORTANT !!!
256  * Across this function, packet decode timestamp (DTS) values are used to
257  * compare given timestamp against. This is done because DTS values shall
258  * monotonically increase during the course of decoding unlike PTS values
259  * which may be affected by frame reordering due to B frames.
260  */
261 
262  if (!is_seekable_) {
263  DemuxCriticalLog("Seek isn't supported for this input.");
264  return false;
265  }
266 
267  if (IsVFR() && (SEEK_CRITERIA_FRAME_NUM == seek_ctx.seek_crit_)) {
268  DemuxCriticalLog("Can't seek by frame number in VFR sequences. Seek by timestamp instead.");
269  return false;
270  }
271  int64_t timestamp = 0;
272  // Seek for single frame;
273  auto seek_frame = [&](VideoSeekContext const& seek_ctx, int flags) {
274  bool seek_backward = true;
275  int ret = 0;
276 
277  switch (seek_ctx.seek_crit_) {
278  case SEEK_CRITERIA_FRAME_NUM:
279  timestamp = TsFromFrameNumber(seek_ctx.seek_frame_);
280  ret = av_seek_frame(av_fmt_input_ctx_, av_stream_, timestamp, seek_backward ? AVSEEK_FLAG_BACKWARD | flags : flags);
281  break;
282  case SEEK_CRITERIA_TIME_STAMP:
283  timestamp = TsFromTime(seek_ctx.seek_frame_);
284  ret = av_seek_frame(av_fmt_input_ctx_, av_stream_, timestamp, seek_backward ? AVSEEK_FLAG_BACKWARD | flags : flags);
285  break;
286  default:
287  DemuxCriticalLog("Invalid seek criteria");
288  ret = -1;
289  }
290 
291  if (ret < 0) {
292  throw std::runtime_error("ERROR: seeking for frame");
293  }
294  };
295 
296  // Check if frame satisfies seek conditions;
297  auto is_seek_done = [&](PacketData& pkt_data, VideoSeekContext const& seek_ctx) {
298  int64_t target_ts = 0;
299 
300  switch (seek_ctx.seek_crit_) {
301  case SEEK_CRITERIA_FRAME_NUM:
302  target_ts = TsFromFrameNumber(seek_ctx.seek_frame_);
303  break;
304  case SEEK_CRITERIA_TIME_STAMP:
305  target_ts = TsFromTime(seek_ctx.seek_frame_);
306  break;
307  default:
308  DemuxCriticalLog("Invalid seek criteria");
309  return -1;
310  }
311 
312  if (pkt_dts_ == target_ts) {
313  return 0;
314  } else if (pkt_dts_ > target_ts) {
315  return 1;
316  } else {
317  return -1;
318  };
319  };
320 
321  /* This will seek for exact frame number;
322  * Note that decoder may not be able to decode such frame; */
323  auto seek_for_exact_frame = [&](PacketData& pkt_data, VideoSeekContext& seek_ctx) {
324  // Repetititive seek until seek condition is satisfied;
325  VideoSeekContext tmp_ctx(seek_ctx.seek_frame_);
326  seek_frame(tmp_ctx, AVSEEK_FLAG_ANY);
327 
328  int seek_done = 0;
329  do {
330  if (!Demux(pp_video, video_size, &pkt_data.pts)) {
331  throw std::runtime_error("ERROR: Demux failed trying to seek for specified frame number/timestamp");
332  }
333  seek_done = is_seek_done(pkt_data, seek_ctx);
334  //TODO: one last condition, check for a target too high than available for timestamp
335  if (seek_done > 0) { // We've gone too far and need to seek backwards;
336  if ((tmp_ctx.seek_frame_--) >= 0) {
337  seek_frame(tmp_ctx, AVSEEK_FLAG_ANY);
338  }
339  } else if (seek_done < 0) { // Need to read more frames until we reach requested number;
340  tmp_ctx.seek_frame_++;
341  seek_frame(tmp_ctx, AVSEEK_FLAG_ANY);
342  }
343  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
344  break;
345  } while (seek_done != 0);
346 
347  seek_ctx.out_frame_pts_ = pkt_data.pts;
348  seek_ctx.out_frame_duration_ = pkt_data.duration = pkt_duration_;
349  seek_ctx.requested_frame_pts_ = (int64_t) (timestamp * default_time_scale_ * time_base_);
350  };
351 
352  // Seek for closest key frame in the past;
353  auto seek_for_prev_key_frame = [&](PacketData& pkt_data, VideoSeekContext& seek_ctx) {
354  seek_frame(seek_ctx, AVSEEK_FLAG_BACKWARD);
355  Demux(pp_video, video_size, &pkt_data.pts);
356  seek_ctx.num_frames_decoded_ = static_cast<uint64_t>(pkt_data.pts / 1000 * frame_rate_);
357  seek_ctx.out_frame_pts_ = pkt_data.pts;
358  seek_ctx.out_frame_duration_ = pkt_data.duration = pkt_duration_;
359  seek_ctx.requested_frame_pts_ = (int64_t) (timestamp * default_time_scale_ * time_base_);
360  };
361 
362  PacketData pktData;
363  pktData.bsl_data = size_t(*pp_video);
364  pktData.bsl = *video_size;
365 
366  switch (seek_ctx.seek_mode_) {
367  case SEEK_MODE_EXACT_FRAME:
368  seek_for_exact_frame(pktData, seek_ctx);
369  break;
370  case SEEK_MODE_PREV_KEY_FRAME:
371  seek_for_prev_key_frame(pktData, seek_ctx);
372  break;
373  default:
374  throw std::runtime_error("ERROR::Unsupported seek mode");
375  break;
376  }
377 
378  return true;
379  }
380  const uint32_t GetWidth() const { return width_;}
381  const uint32_t GetHeight() const { return height_;}
382  const uint32_t GetChromaHeight() const { return chroma_height_;}
383  const uint32_t GetBitDepth() const { return bit_depth_;}
384  const uint32_t GetBytePerPixel() const { return byte_per_pixel_;}
385  const uint32_t GetBitRate() const { return bit_rate_;}
386  const double GetFrameRate() const {return frame_rate_;};
387  bool IsVFR() const { return frame_rate_ != avg_frame_rate_; };
388  int64_t TsFromTime(double ts_sec) {
389  // Convert integer timestamp representation to AV_TIME_BASE and switch to fixed_point
390  auto const ts_tbu = llround(ts_sec * AV_TIME_BASE);
391  // Rescale the timestamp to value represented in stream base units;
392  AVRational time_factor = {1, AV_TIME_BASE};
393  return av_rescale_q(ts_tbu, time_factor, av_fmt_input_ctx_->streams[av_stream_]->time_base);
394  }
395 
396  int64_t TsFromFrameNumber(int64_t frame_num) {
397  auto const ts_sec = static_cast<double>(frame_num) / frame_rate_;
398  return TsFromTime(ts_sec);
399  }
400 
401  private:
402  VideoDemuxer(AVFormatContext *av_fmt_input_ctx) : av_fmt_input_ctx_(av_fmt_input_ctx) {
403  av_log_set_level(AV_LOG_QUIET);
404  if (!av_fmt_input_ctx_) {
405  DemuxCriticalLog("av_fmt_input_ctx_ is not valid!");
406  return;
407  }
408  packet_ = av_packet_alloc();
409  packet_filtered_ = av_packet_alloc();
410  if (!packet_ || !packet_filtered_) {
411  DemuxCriticalLog("av_packet_alloc failed!");
412  return;
413  }
414  if (avformat_find_stream_info(av_fmt_input_ctx_, nullptr) < 0) {
415  DemuxCriticalLog("avformat_find_stream_info failed!");
416  return;
417  }
418  av_stream_ = av_find_best_stream(av_fmt_input_ctx_, AVMEDIA_TYPE_VIDEO, -1, -1, nullptr, 0);
419  if (av_stream_ < 0) {
420  DemuxCriticalLog("av_find_best_stream failed!");
421  av_packet_free(&packet_);
422  av_packet_free(&packet_filtered_);
423  return;
424  }
425  av_video_codec_id_ = av_fmt_input_ctx_->streams[av_stream_]->codecpar->codec_id;
426  width_ = av_fmt_input_ctx_->streams[av_stream_]->codecpar->width;
427  height_ = av_fmt_input_ctx_->streams[av_stream_]->codecpar->height;
428  chroma_format_ = (AVPixelFormat)av_fmt_input_ctx_->streams[av_stream_]->codecpar->format;
429  bit_rate_ = av_fmt_input_ctx_->streams[av_stream_]->codecpar->bit_rate;
430  if (av_fmt_input_ctx_->streams[av_stream_]->r_frame_rate.den != 0)
431  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);
432  if (av_fmt_input_ctx_->streams[av_stream_]->avg_frame_rate.den != 0)
433  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);
434 
435  switch (chroma_format_) {
436  case AV_PIX_FMT_YUV420P10LE:
437  case AV_PIX_FMT_GRAY10LE:
438  bit_depth_ = 10;
439  chroma_height_ = (height_ + 1) >> 1;
440  byte_per_pixel_ = 2;
441  break;
442  case AV_PIX_FMT_YUV420P12LE:
443  bit_depth_ = 12;
444  chroma_height_ = (height_ + 1) >> 1;
445  byte_per_pixel_ = 2;
446  break;
447  case AV_PIX_FMT_YUV444P10LE:
448  bit_depth_ = 10;
449  chroma_height_ = height_ << 1;
450  byte_per_pixel_ = 2;
451  break;
452  case AV_PIX_FMT_YUV444P12LE:
453  bit_depth_ = 12;
454  chroma_height_ = height_ << 1;
455  byte_per_pixel_ = 2;
456  break;
457  case AV_PIX_FMT_YUV444P:
458  bit_depth_ = 8;
459  chroma_height_ = height_ << 1;
460  byte_per_pixel_ = 1;
461  break;
462  case AV_PIX_FMT_YUV420P:
463  case AV_PIX_FMT_YUVJ420P:
464  case AV_PIX_FMT_YUVJ422P:
465  case AV_PIX_FMT_YUVJ444P:
466  case AV_PIX_FMT_GRAY8:
467  bit_depth_ = 8;
468  chroma_height_ = (height_ + 1) >> 1;
469  byte_per_pixel_ = 1;
470  break;
471  default:
472  chroma_format_ = AV_PIX_FMT_YUV420P;
473  bit_depth_ = 8;
474  chroma_height_ = (height_ + 1) >> 1;
475  byte_per_pixel_ = 1;
476  }
477 
478  AVRational time_base = av_fmt_input_ctx_->streams[av_stream_]->time_base;
479  time_base_ = av_q2d(time_base);
480 
481  is_h264_ = av_video_codec_id_ == AV_CODEC_ID_H264 && (!strcmp(av_fmt_input_ctx_->iformat->long_name, "QuickTime / MOV")
482  || !strcmp(av_fmt_input_ctx_->iformat->long_name, "FLV (Flash Video)")
483  || !strcmp(av_fmt_input_ctx_->iformat->long_name, "Matroska / WebM"));
484  is_hevc_ = av_video_codec_id_ == AV_CODEC_ID_HEVC && (!strcmp(av_fmt_input_ctx_->iformat->long_name, "QuickTime / MOV")
485  || !strcmp(av_fmt_input_ctx_->iformat->long_name, "FLV (Flash Video)")
486  || !strcmp(av_fmt_input_ctx_->iformat->long_name, "Matroska / WebM"));
487  is_mpeg4_ = av_video_codec_id_ == AV_CODEC_ID_MPEG4 && (!strcmp(av_fmt_input_ctx_->iformat->long_name, "QuickTime / MOV")
488  || !strcmp(av_fmt_input_ctx_->iformat->long_name, "FLV (Flash Video)")
489  || !strcmp(av_fmt_input_ctx_->iformat->long_name, "Matroska / WebM"));
490 
491  // Check if the input file allow seek functionality.
492 #if USE_AVCODEC_GREATER_THAN_58_134
493  is_seekable_ = true; //for latest version of FFMPeg, read_seek and read_seek2 is not exposed in AVFormatContext
494 #else
495  is_seekable_ = av_fmt_input_ctx_->iformat->read_seek || av_fmt_input_ctx_->iformat->read_seek2;
496 #endif
497 
498  if (is_h264_) {
499  const AVBitStreamFilter *bsf = av_bsf_get_by_name("h264_mp4toannexb");
500  if (!bsf) {
501  DemuxCriticalLog("av_bsf_get_by_name() failed for h264_mp4toannexb");
502  av_packet_free(&packet_);
503  av_packet_free(&packet_filtered_);
504  return;
505  }
506  if (av_bsf_alloc(bsf, &av_bsf_ctx_) != 0) {
507  DemuxCriticalLog("av_bsf_alloc failed!");
508  return;
509  }
510  avcodec_parameters_copy(av_bsf_ctx_->par_in, av_fmt_input_ctx_->streams[av_stream_]->codecpar);
511  if (av_bsf_init(av_bsf_ctx_) < 0) {
512  DemuxCriticalLog("av_bsf_init failed!");
513  return;
514  }
515  }
516  if (is_hevc_) {
517  const AVBitStreamFilter *bsf = av_bsf_get_by_name("hevc_mp4toannexb");
518  if (!bsf) {
519  DemuxCriticalLog("av_bsf_get_by_name() failed for hevc_mp4toannexb");
520  av_packet_free(&packet_);
521  av_packet_free(&packet_filtered_);
522  return;
523  }
524  if (av_bsf_alloc(bsf, &av_bsf_ctx_) != 0 ) {
525  DemuxCriticalLog("av_bsf_alloc failed!");
526  return;
527  }
528  avcodec_parameters_copy(av_bsf_ctx_->par_in, av_fmt_input_ctx_->streams[av_stream_]->codecpar);
529  if (av_bsf_init(av_bsf_ctx_) < 0) {
530  DemuxCriticalLog("av_bsf_init failed!");
531  return;
532  }
533  }
534  }
535  AVFormatContext *CreateFmtContextUtil(StreamProvider *stream_provider) {
536  AVFormatContext *ctx = nullptr;
537  if (!(ctx = avformat_alloc_context())) {
538  DemuxCriticalLog("avformat_alloc_context failed!");
539  return nullptr;
540  }
541  uint8_t *avioc_buffer = nullptr;
542  int avioc_buffer_size = stream_provider->GetBufferSize();
543  avioc_buffer = (uint8_t *)av_malloc(avioc_buffer_size);
544  if (!avioc_buffer) {
545  DemuxCriticalLog("av_malloc failed!");
546  return nullptr;
547  }
548  av_io_ctx_ = avio_alloc_context(avioc_buffer, avioc_buffer_size,
549  0, stream_provider, &ReadPacket, nullptr, nullptr);
550  if (!av_io_ctx_) {
551  DemuxCriticalLog("avio_alloc_context failed!");
552  return nullptr;
553  }
554  ctx->pb = av_io_ctx_;
555 
556  if (avformat_open_input(&ctx, nullptr, nullptr, nullptr) != 0) {
557  DemuxCriticalLog("avformat_open_input failed!");
558  return nullptr;
559  }
560  return ctx;
561  }
562  AVFormatContext *CreateFmtContextUtil(const char *input_file_path) {
563  avformat_network_init();
564  AVFormatContext *ctx = nullptr;
565  if (avformat_open_input(&ctx, input_file_path, nullptr, nullptr) != 0 ) {
566  DemuxCriticalLog("avformat_open_input failed!");
567  return nullptr;
568  }
569  return ctx;
570  }
571  static int ReadPacket(void *data, uint8_t *buf, int buf_size) {
572  return ((StreamProvider *)data)->GetData(buf, buf_size);
573  }
574  AVFormatContext *av_fmt_input_ctx_ = nullptr;
575  AVIOContext *av_io_ctx_ = nullptr;
576  AVPacket* packet_ = nullptr;
577  AVPacket* packet_filtered_ = nullptr;
578  AVBSFContext *av_bsf_ctx_ = nullptr;
579  AVCodecID av_video_codec_id_;
580  AVPixelFormat chroma_format_;
581  double frame_rate_ = 0.0;
582  double avg_frame_rate_ = 0.0;
583  uint8_t *data_with_header_ = nullptr;
584  int av_stream_ = 0;
585  bool is_h264_ = false;
586  bool is_hevc_ = false;
587  bool is_mpeg4_ = false;
588  bool is_seekable_ = false;
589  int64_t default_time_scale_ = 1000;
590  double time_base_ = 0.0;
591  uint32_t frame_count_ = 0;
592  uint32_t width_ = 0;
593  uint32_t height_ = 0;
594  uint32_t chroma_height_ = 0;
595  uint32_t bit_depth_ = 0;
596  uint32_t byte_per_pixel_ = 0;
597  uint32_t bit_rate_ = 0;
598  // used for Seek Exact frame
599  int64_t pkt_dts_ = 0;
600  int64_t pkt_duration_ = 0;
601 };
602 
603 static inline rocDecVideoCodec AVCodec2RocDecVideoCodec(AVCodecID av_codec) {
604  switch (av_codec) {
605  case AV_CODEC_ID_MPEG1VIDEO : return rocDecVideoCodec_MPEG1;
606  case AV_CODEC_ID_MPEG2VIDEO : return rocDecVideoCodec_MPEG2;
607  case AV_CODEC_ID_MPEG4 : return rocDecVideoCodec_MPEG4;
608  case AV_CODEC_ID_H264 : return rocDecVideoCodec_AVC;
609  case AV_CODEC_ID_HEVC : return rocDecVideoCodec_HEVC;
610  case AV_CODEC_ID_VP8 : return rocDecVideoCodec_VP8;
611  case AV_CODEC_ID_VP9 : return rocDecVideoCodec_VP9;
612  case AV_CODEC_ID_MJPEG : return rocDecVideoCodec_JPEG;
613  case AV_CODEC_ID_AV1 : return rocDecVideoCodec_AV1;
614  default : return rocDecVideoCodec_NumCodecs;
615  }
616 }
Definition: video_demuxer.h:154
Definition: video_demuxer.h:152
Definition: video_demuxer.h:101
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:91
SeekModeEnum
Enum for Seek mode.
Definition: video_demuxer.h:75
enum SeekModeEnum SeekMode
Enum for Seek mode.
SeekCriteriaEnum
Enum for Seek Criteria.
Definition: video_demuxer.h:85
enum SeekCriteriaEnum SeekCriteria
Enum for Seek Criteria.