OpenShot Library | libopenshot  0.5.0
FFmpegReader.cpp
Go to the documentation of this file.
1 
12 // Copyright (c) 2008-2024 OpenShot Studios, LLC, Fabrice Bellard
13 //
14 // SPDX-License-Identifier: LGPL-3.0-or-later
15 
16 #include <thread> // for std::this_thread::sleep_for
17 #include <chrono> // for std::chrono::milliseconds
18 #include <algorithm>
19 #include <cmath>
20 #include <sstream>
21 #include <unistd.h>
22 
23 #include "FFmpegUtilities.h"
24 #include "effects/CropHelpers.h"
25 
26 #include "FFmpegReader.h"
27 #include "Exceptions.h"
28 #include "MemoryTrim.h"
29 #include "Timeline.h"
30 #include "ZmqLogger.h"
31 
32 #define ENABLE_VAAPI 0
33 
34 #if USE_HW_ACCEL
35 #define MAX_SUPPORTED_WIDTH 1950
36 #define MAX_SUPPORTED_HEIGHT 1100
37 
38 #if ENABLE_VAAPI
39 #include "libavutil/hwcontext_vaapi.h"
40 
41 typedef struct VAAPIDecodeContext {
42  VAProfile va_profile;
43  VAEntrypoint va_entrypoint;
44  VAConfigID va_config;
45  VAContextID va_context;
46 
47 #if FF_API_STRUCT_VAAPI_CONTEXT
48  // FF_DISABLE_DEPRECATION_WARNINGS
49  int have_old_context;
50  struct vaapi_context *old_context;
51  AVBufferRef *device_ref;
52  // FF_ENABLE_DEPRECATION_WARNINGS
53 #endif
54 
55  AVHWDeviceContext *device;
56  AVVAAPIDeviceContext *hwctx;
57 
58  AVHWFramesContext *frames;
59  AVVAAPIFramesContext *hwfc;
60 
61  enum AVPixelFormat surface_format;
62  int surface_count;
63  } VAAPIDecodeContext;
64 #endif // ENABLE_VAAPI
65 #endif // USE_HW_ACCEL
66 
67 
68 using namespace openshot;
69 
70 int hw_de_on = 0;
71 #if USE_HW_ACCEL
72  AVPixelFormat hw_de_av_pix_fmt_global = AV_PIX_FMT_NONE;
73  AVHWDeviceType hw_de_av_device_type_global = AV_HWDEVICE_TYPE_NONE;
74 #endif
75 
76 FFmpegReader::FFmpegReader(const std::string &path, bool inspect_reader)
77  : FFmpegReader(path, DurationStrategy::VideoPreferred, inspect_reader) {}
78 
79 FFmpegReader::FFmpegReader(const std::string &path, DurationStrategy duration_strategy, bool inspect_reader)
80  : last_frame(0), is_seeking(0), seeking_pts(0), seeking_frame(0), seek_count(0), NO_PTS_OFFSET(-99999),
81  path(path), is_video_seek(true), check_interlace(false), check_fps(false), enable_seek(true), is_open(false),
82  seek_audio_frame_found(0), seek_video_frame_found(0),is_duration_known(false), largest_frame_processed(0),
83  current_video_frame(0), packet(NULL), duration_strategy(duration_strategy),
84  audio_pts(0), video_pts(0), pFormatCtx(NULL), videoStream(-1), audioStream(-1), pCodecCtx(NULL), aCodecCtx(NULL),
85  pStream(NULL), aStream(NULL), pFrame(NULL), previous_packet_location{-1,0},
86  hold_packet(false) {
87 
88  // Initialize FFMpeg, and register all formats and codecs
91 
92  // Init timestamp offsets
93  pts_offset_seconds = NO_PTS_OFFSET;
94  video_pts_seconds = NO_PTS_OFFSET;
95  audio_pts_seconds = NO_PTS_OFFSET;
96 
97  // Init cache
98  working_cache.SetMaxBytesFromInfo(info.fps.ToDouble() * 2, info.width, info.height, info.sample_rate, info.channels);
99  final_cache.SetMaxBytesFromInfo(24, info.width, info.height, info.sample_rate, info.channels);
100 
101  // Open and Close the reader, to populate its attributes (such as height, width, etc...)
102  if (inspect_reader) {
103  Open();
104  Close();
105  }
106 }
107 
109  if (is_open)
110  // Auto close reader if not already done
111  Close();
112 }
113 
114 // This struct holds the associated video frame and starting sample # for an audio packet.
115 bool AudioLocation::is_near(AudioLocation location, int samples_per_frame, int64_t amount) {
116  // Is frame even close to this one?
117  if (abs(location.frame - frame) >= 2)
118  // This is too far away to be considered
119  return false;
120 
121  // Note that samples_per_frame can vary slightly frame to frame when the
122  // audio sampling rate is not an integer multiple of the video fps.
123  int64_t diff = samples_per_frame * (location.frame - frame) + location.sample_start - sample_start;
124  if (abs(diff) <= amount)
125  // close
126  return true;
127 
128  // not close
129  return false;
130 }
131 
132 #if USE_HW_ACCEL
133 
134 // Get hardware pix format
135 static enum AVPixelFormat get_hw_dec_format(AVCodecContext *ctx, const enum AVPixelFormat *pix_fmts)
136 {
137  const enum AVPixelFormat *p;
138 
139  for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) {
140  switch (*p) {
141 #if defined(__linux__)
142  // Linux pix formats
143  case AV_PIX_FMT_VAAPI:
144  hw_de_av_pix_fmt_global = AV_PIX_FMT_VAAPI;
145  hw_de_av_device_type_global = AV_HWDEVICE_TYPE_VAAPI;
146  return *p;
147  break;
148  case AV_PIX_FMT_VDPAU:
149  hw_de_av_pix_fmt_global = AV_PIX_FMT_VDPAU;
150  hw_de_av_device_type_global = AV_HWDEVICE_TYPE_VDPAU;
151  return *p;
152  break;
153 #endif
154 #if defined(_WIN32)
155  // Windows pix formats
156  case AV_PIX_FMT_DXVA2_VLD:
157  hw_de_av_pix_fmt_global = AV_PIX_FMT_DXVA2_VLD;
158  hw_de_av_device_type_global = AV_HWDEVICE_TYPE_DXVA2;
159  return *p;
160  break;
161  case AV_PIX_FMT_D3D11:
162  hw_de_av_pix_fmt_global = AV_PIX_FMT_D3D11;
163  hw_de_av_device_type_global = AV_HWDEVICE_TYPE_D3D11VA;
164  return *p;
165  break;
166 #endif
167 #if defined(__APPLE__)
168  // Apple pix formats
169  case AV_PIX_FMT_VIDEOTOOLBOX:
170  hw_de_av_pix_fmt_global = AV_PIX_FMT_VIDEOTOOLBOX;
171  hw_de_av_device_type_global = AV_HWDEVICE_TYPE_VIDEOTOOLBOX;
172  return *p;
173  break;
174 #endif
175  // Cross-platform pix formats
176  case AV_PIX_FMT_CUDA:
177  hw_de_av_pix_fmt_global = AV_PIX_FMT_CUDA;
178  hw_de_av_device_type_global = AV_HWDEVICE_TYPE_CUDA;
179  return *p;
180  break;
181  case AV_PIX_FMT_QSV:
182  hw_de_av_pix_fmt_global = AV_PIX_FMT_QSV;
183  hw_de_av_device_type_global = AV_HWDEVICE_TYPE_QSV;
184  return *p;
185  break;
186  default:
187  // This is only here to silence unused-enum warnings
188  break;
189  }
190  }
191  ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::get_hw_dec_format (Unable to decode this file using hardware decode)");
192  return AV_PIX_FMT_NONE;
193 }
194 
195 int FFmpegReader::IsHardwareDecodeSupported(int codecid)
196 {
197  int ret;
198  switch (codecid) {
199  case AV_CODEC_ID_H264:
200  case AV_CODEC_ID_MPEG2VIDEO:
201  case AV_CODEC_ID_VC1:
202  case AV_CODEC_ID_WMV1:
203  case AV_CODEC_ID_WMV2:
204  case AV_CODEC_ID_WMV3:
205  ret = 1;
206  break;
207  default :
208  ret = 0;
209  break;
210  }
211  return ret;
212 }
213 #endif // USE_HW_ACCEL
214 
216  // Open reader if not already open
217  if (!is_open) {
218  // Prevent async calls to the following code
219  const std::lock_guard<std::recursive_mutex> lock(getFrameMutex);
220 
221  // Initialize format context
222  pFormatCtx = NULL;
223  {
225  ZmqLogger::Instance()->AppendDebugMethod("Decode hardware acceleration settings", "hw_de_on", hw_de_on, "HARDWARE_DECODER", openshot::Settings::Instance()->HARDWARE_DECODER);
226  }
227 
228  // Open video file
229  if (avformat_open_input(&pFormatCtx, path.c_str(), NULL, NULL) != 0)
230  throw InvalidFile("File could not be opened.", path);
231 
232  // Retrieve stream information
233  if (avformat_find_stream_info(pFormatCtx, NULL) < 0)
234  throw NoStreamsFound("No streams found in file.", path);
235 
236  videoStream = -1;
237  audioStream = -1;
238 
239  // Init end-of-file detection variables
240  packet_status.reset(true);
241 
242  // Loop through each stream, and identify the video and audio stream index
243  for (unsigned int i = 0; i < pFormatCtx->nb_streams; i++) {
244  // Is this a video stream?
245  if (AV_GET_CODEC_TYPE(pFormatCtx->streams[i]) == AVMEDIA_TYPE_VIDEO && videoStream < 0) {
246  videoStream = i;
247  packet_status.video_eof = false;
248  packet_status.packets_eof = false;
249  packet_status.end_of_file = false;
250  }
251  // Is this an audio stream?
252  if (AV_GET_CODEC_TYPE(pFormatCtx->streams[i]) == AVMEDIA_TYPE_AUDIO && audioStream < 0) {
253  audioStream = i;
254  packet_status.audio_eof = false;
255  packet_status.packets_eof = false;
256  packet_status.end_of_file = false;
257  }
258  }
259  if (videoStream == -1 && audioStream == -1)
260  throw NoStreamsFound("No video or audio streams found in this file.", path);
261 
262  // Is there a video stream?
263  if (videoStream != -1) {
264  // Set the stream index
265  info.video_stream_index = videoStream;
266 
267  // Set the codec and codec context pointers
268  pStream = pFormatCtx->streams[videoStream];
269 
270  // Find the codec ID from stream
271  const AVCodecID codecId = AV_FIND_DECODER_CODEC_ID(pStream);
272 
273  // Get codec and codec context from stream
274  const AVCodec *pCodec = avcodec_find_decoder(codecId);
275  AVDictionary *opts = NULL;
276  int retry_decode_open = 2;
277  // If hw accel is selected but hardware cannot handle repeat with software decoding
278  do {
279  pCodecCtx = AV_GET_CODEC_CONTEXT(pStream, pCodec);
280 #if USE_HW_ACCEL
281  if (hw_de_on && (retry_decode_open==2)) {
282  // Up to here no decision is made if hardware or software decode
283  hw_de_supported = IsHardwareDecodeSupported(pCodecCtx->codec_id);
284  }
285 #endif
286  retry_decode_open = 0;
287 
288  // Set number of threads equal to number of processors (not to exceed 16)
289  pCodecCtx->thread_count = std::min(FF_VIDEO_NUM_PROCESSORS, 16);
290 
291  if (pCodec == NULL) {
292  throw InvalidCodec("A valid video codec could not be found for this file.", path);
293  }
294 
295  // Init options
296  av_dict_set(&opts, "strict", "experimental", 0);
297 #if USE_HW_ACCEL
298  if (hw_de_on && hw_de_supported) {
299  // Open Hardware Acceleration
300  int i_decoder_hw = 0;
301  char adapter[256];
302  char *adapter_ptr = NULL;
303  int adapter_num;
305  fprintf(stderr, "Hardware decoding device number: %d\n", adapter_num);
306 
307  // Set hardware pix format (callback)
308  pCodecCtx->get_format = get_hw_dec_format;
309 
310  if (adapter_num < 3 && adapter_num >=0) {
311 #if defined(__linux__)
312  snprintf(adapter,sizeof(adapter),"/dev/dri/renderD%d", adapter_num+128);
313  adapter_ptr = adapter;
315  switch (i_decoder_hw) {
316  case 1:
317  hw_de_av_device_type = AV_HWDEVICE_TYPE_VAAPI;
318  break;
319  case 2:
320  hw_de_av_device_type = AV_HWDEVICE_TYPE_CUDA;
321  break;
322  case 6:
323  hw_de_av_device_type = AV_HWDEVICE_TYPE_VDPAU;
324  break;
325  case 7:
326  hw_de_av_device_type = AV_HWDEVICE_TYPE_QSV;
327  break;
328  default:
329  hw_de_av_device_type = AV_HWDEVICE_TYPE_VAAPI;
330  break;
331  }
332 
333 #elif defined(_WIN32)
334  adapter_ptr = NULL;
336  switch (i_decoder_hw) {
337  case 2:
338  hw_de_av_device_type = AV_HWDEVICE_TYPE_CUDA;
339  break;
340  case 3:
341  hw_de_av_device_type = AV_HWDEVICE_TYPE_DXVA2;
342  break;
343  case 4:
344  hw_de_av_device_type = AV_HWDEVICE_TYPE_D3D11VA;
345  break;
346  case 7:
347  hw_de_av_device_type = AV_HWDEVICE_TYPE_QSV;
348  break;
349  default:
350  hw_de_av_device_type = AV_HWDEVICE_TYPE_DXVA2;
351  break;
352  }
353 #elif defined(__APPLE__)
354  adapter_ptr = NULL;
356  switch (i_decoder_hw) {
357  case 5:
358  hw_de_av_device_type = AV_HWDEVICE_TYPE_VIDEOTOOLBOX;
359  break;
360  case 7:
361  hw_de_av_device_type = AV_HWDEVICE_TYPE_QSV;
362  break;
363  default:
364  hw_de_av_device_type = AV_HWDEVICE_TYPE_VIDEOTOOLBOX;
365  break;
366  }
367 #endif
368 
369  } else {
370  adapter_ptr = NULL; // Just to be sure
371  }
372 
373  // Check if it is there and writable
374 #if defined(__linux__)
375  if( adapter_ptr != NULL && access( adapter_ptr, W_OK ) == 0 ) {
376 #elif defined(_WIN32)
377  if( adapter_ptr != NULL ) {
378 #elif defined(__APPLE__)
379  if( adapter_ptr != NULL ) {
380 #endif
381  ZmqLogger::Instance()->AppendDebugMethod("Decode Device present using device");
382  }
383  else {
384  adapter_ptr = NULL; // use default
385  ZmqLogger::Instance()->AppendDebugMethod("Decode Device not present using default");
386  }
387 
388  hw_device_ctx = NULL;
389  // Here the first hardware initialisations are made
390  if (av_hwdevice_ctx_create(&hw_device_ctx, hw_de_av_device_type, adapter_ptr, NULL, 0) >= 0) {
391  if (!(pCodecCtx->hw_device_ctx = av_buffer_ref(hw_device_ctx))) {
392  throw InvalidCodec("Hardware device reference create failed.", path);
393  }
394 
395  /*
396  av_buffer_unref(&ist->hw_frames_ctx);
397  ist->hw_frames_ctx = av_hwframe_ctx_alloc(hw_device_ctx);
398  if (!ist->hw_frames_ctx) {
399  av_log(avctx, AV_LOG_ERROR, "Error creating a CUDA frames context\n");
400  return AVERROR(ENOMEM);
401  }
402 
403  frames_ctx = (AVHWFramesContext*)ist->hw_frames_ctx->data;
404 
405  frames_ctx->format = AV_PIX_FMT_CUDA;
406  frames_ctx->sw_format = avctx->sw_pix_fmt;
407  frames_ctx->width = avctx->width;
408  frames_ctx->height = avctx->height;
409 
410  av_log(avctx, AV_LOG_DEBUG, "Initializing CUDA frames context: sw_format = %s, width = %d, height = %d\n",
411  av_get_pix_fmt_name(frames_ctx->sw_format), frames_ctx->width, frames_ctx->height);
412 
413 
414  ret = av_hwframe_ctx_init(pCodecCtx->hw_device_ctx);
415  ret = av_hwframe_ctx_init(ist->hw_frames_ctx);
416  if (ret < 0) {
417  av_log(avctx, AV_LOG_ERROR, "Error initializing a CUDA frame pool\n");
418  return ret;
419  }
420  */
421  }
422  else {
423  throw InvalidCodec("Hardware device create failed.", path);
424  }
425  }
426 #endif // USE_HW_ACCEL
427 
428  // Disable per-frame threading for album arts
429  // Using FF_THREAD_FRAME adds one frame decoding delay per thread,
430  // but there's only one frame in this case.
431  if (HasAlbumArt())
432  {
433  pCodecCtx->thread_type &= ~FF_THREAD_FRAME;
434  }
435 
436  // Open video codec
437  int avcodec_return = avcodec_open2(pCodecCtx, pCodec, &opts);
438  if (avcodec_return < 0) {
439  std::stringstream avcodec_error_msg;
440  avcodec_error_msg << "A video codec was found, but could not be opened. Error: " << av_err2string(avcodec_return);
441  throw InvalidCodec(avcodec_error_msg.str(), path);
442  }
443 
444 #if USE_HW_ACCEL
445  if (hw_de_on && hw_de_supported) {
446  AVHWFramesConstraints *constraints = NULL;
447  void *hwconfig = NULL;
448  hwconfig = av_hwdevice_hwconfig_alloc(hw_device_ctx);
449 
450 // TODO: needs va_config!
451 #if ENABLE_VAAPI
452  ((AVVAAPIHWConfig *)hwconfig)->config_id = ((VAAPIDecodeContext *)(pCodecCtx->priv_data))->va_config;
453  constraints = av_hwdevice_get_hwframe_constraints(hw_device_ctx,hwconfig);
454 #endif // ENABLE_VAAPI
455  if (constraints) {
456  if (pCodecCtx->coded_width < constraints->min_width ||
457  pCodecCtx->coded_height < constraints->min_height ||
458  pCodecCtx->coded_width > constraints->max_width ||
459  pCodecCtx->coded_height > constraints->max_height) {
460  ZmqLogger::Instance()->AppendDebugMethod("DIMENSIONS ARE TOO LARGE for hardware acceleration\n");
461  hw_de_supported = 0;
462  retry_decode_open = 1;
463  AV_FREE_CONTEXT(pCodecCtx);
464  if (hw_device_ctx) {
465  av_buffer_unref(&hw_device_ctx);
466  hw_device_ctx = NULL;
467  }
468  }
469  else {
470  // All is just peachy
471  ZmqLogger::Instance()->AppendDebugMethod("\nDecode hardware acceleration is used\n", "Min width :", constraints->min_width, "Min Height :", constraints->min_height, "MaxWidth :", constraints->max_width, "MaxHeight :", constraints->max_height, "Frame width :", pCodecCtx->coded_width, "Frame height :", pCodecCtx->coded_height);
472  retry_decode_open = 0;
473  }
474  av_hwframe_constraints_free(&constraints);
475  if (hwconfig) {
476  av_freep(&hwconfig);
477  }
478  }
479  else {
480  int max_h, max_w;
481  //max_h = ((getenv( "LIMIT_HEIGHT_MAX" )==NULL) ? MAX_SUPPORTED_HEIGHT : atoi(getenv( "LIMIT_HEIGHT_MAX" )));
483  //max_w = ((getenv( "LIMIT_WIDTH_MAX" )==NULL) ? MAX_SUPPORTED_WIDTH : atoi(getenv( "LIMIT_WIDTH_MAX" )));
485  ZmqLogger::Instance()->AppendDebugMethod("Constraints could not be found using default limit\n");
486  //cerr << "Constraints could not be found using default limit\n";
487  if (pCodecCtx->coded_width < 0 ||
488  pCodecCtx->coded_height < 0 ||
489  pCodecCtx->coded_width > max_w ||
490  pCodecCtx->coded_height > max_h ) {
491  ZmqLogger::Instance()->AppendDebugMethod("DIMENSIONS ARE TOO LARGE for hardware acceleration\n", "Max Width :", max_w, "Max Height :", max_h, "Frame width :", pCodecCtx->coded_width, "Frame height :", pCodecCtx->coded_height);
492  hw_de_supported = 0;
493  retry_decode_open = 1;
494  AV_FREE_CONTEXT(pCodecCtx);
495  if (hw_device_ctx) {
496  av_buffer_unref(&hw_device_ctx);
497  hw_device_ctx = NULL;
498  }
499  }
500  else {
501  ZmqLogger::Instance()->AppendDebugMethod("\nDecode hardware acceleration is used\n", "Max Width :", max_w, "Max Height :", max_h, "Frame width :", pCodecCtx->coded_width, "Frame height :", pCodecCtx->coded_height);
502  retry_decode_open = 0;
503  }
504  }
505  } // if hw_de_on && hw_de_supported
506  else {
507  ZmqLogger::Instance()->AppendDebugMethod("\nDecode in software is used\n");
508  }
509 #else
510  retry_decode_open = 0;
511 #endif // USE_HW_ACCEL
512  } while (retry_decode_open); // retry_decode_open
513  // Free options
514  av_dict_free(&opts);
515 
516  // Update the File Info struct with video details (if a video stream is found)
517  UpdateVideoInfo();
518  }
519 
520  // Is there an audio stream?
521  if (audioStream != -1) {
522  // Set the stream index
523  info.audio_stream_index = audioStream;
524 
525  // Get a pointer to the codec context for the audio stream
526  aStream = pFormatCtx->streams[audioStream];
527 
528  // Find the codec ID from stream
529  AVCodecID codecId = AV_FIND_DECODER_CODEC_ID(aStream);
530 
531  // Get codec and codec context from stream
532  const AVCodec *aCodec = avcodec_find_decoder(codecId);
533  aCodecCtx = AV_GET_CODEC_CONTEXT(aStream, aCodec);
534 
535  // Audio encoding does not typically use more than 2 threads (most codecs use 1 thread)
536  aCodecCtx->thread_count = std::min(FF_AUDIO_NUM_PROCESSORS, 2);
537 
538  if (aCodec == NULL) {
539  throw InvalidCodec("A valid audio codec could not be found for this file.", path);
540  }
541 
542  // Init options
543  AVDictionary *opts = NULL;
544  av_dict_set(&opts, "strict", "experimental", 0);
545 
546  // Open audio codec
547  if (avcodec_open2(aCodecCtx, aCodec, &opts) < 0)
548  throw InvalidCodec("An audio codec was found, but could not be opened.", path);
549 
550  // Free options
551  av_dict_free(&opts);
552 
553  // Update the File Info struct with audio details (if an audio stream is found)
554  UpdateAudioInfo();
555  }
556 
557  // Add format metadata (if any)
558  AVDictionaryEntry *tag = NULL;
559  while ((tag = av_dict_get(pFormatCtx->metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) {
560  QString str_key = tag->key;
561  QString str_value = tag->value;
562  info.metadata[str_key.toStdString()] = str_value.trimmed().toStdString();
563  }
564 
565  // Process video stream side data (rotation, spherical metadata, etc)
566  for (unsigned int i = 0; i < pFormatCtx->nb_streams; i++) {
567  AVStream* st = pFormatCtx->streams[i];
568  if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
569  // Only inspect the first video stream
570  for (int j = 0; j < st->nb_side_data; j++) {
571  AVPacketSideData *sd = &st->side_data[j];
572 
573  // Handle rotation metadata (unchanged)
574  if (sd->type == AV_PKT_DATA_DISPLAYMATRIX &&
575  sd->size >= 9 * sizeof(int32_t) &&
576  !info.metadata.count("rotate"))
577  {
578  double rotation = -av_display_rotation_get(
579  reinterpret_cast<int32_t *>(sd->data));
580  if (std::isnan(rotation)) rotation = 0;
581  info.metadata["rotate"] = std::to_string(rotation);
582  }
583  // Handle spherical video metadata
584  else if (sd->type == AV_PKT_DATA_SPHERICAL) {
585  // Always mark as spherical
586  info.metadata["spherical"] = "1";
587 
588  // Cast the raw bytes to an AVSphericalMapping
589  const AVSphericalMapping* map =
590  reinterpret_cast<const AVSphericalMapping*>(sd->data);
591 
592  // Projection enum → string
593  const char* proj_name = av_spherical_projection_name(map->projection);
594  info.metadata["spherical_projection"] = proj_name
595  ? proj_name
596  : "unknown";
597 
598  // Convert 16.16 fixed-point to float degrees
599  auto to_deg = [](int32_t v){
600  return (double)v / 65536.0;
601  };
602  info.metadata["spherical_yaw"] = std::to_string(to_deg(map->yaw));
603  info.metadata["spherical_pitch"] = std::to_string(to_deg(map->pitch));
604  info.metadata["spherical_roll"] = std::to_string(to_deg(map->roll));
605  }
606  }
607  break;
608  }
609  }
610 
611  // Init previous audio location to zero
612  previous_packet_location.frame = -1;
613  previous_packet_location.sample_start = 0;
614 
615  // Adjust cache size based on size of frame and audio
618 
619  // Scan PTS for any offsets (i.e. non-zero starting streams). At least 1 stream must start at zero timestamp.
620  // This method allows us to shift timestamps to ensure at least 1 stream is starting at zero.
621  UpdatePTSOffset();
622 
623  // Override an invalid framerate
624  if (info.fps.ToFloat() > 240.0f || (info.fps.num <= 0 || info.fps.den <= 0) || info.video_length <= 0) {
625  // Calculate FPS, duration, video bit rate, and video length manually
626  // by scanning through all the video stream packets
627  CheckFPS();
628  }
629 
630  // Mark as "open"
631  is_open = true;
632 
633  // Seek back to beginning of file (if not already seeking)
634  if (!is_seeking) {
635  Seek(1);
636  }
637  }
638 }
639 
641  // Close all objects, if reader is 'open'
642  if (is_open) {
643  // Prevent async calls to the following code
644  const std::lock_guard<std::recursive_mutex> lock(getFrameMutex);
645 
646  // Mark as "closed"
647  is_open = false;
648 
649  // Keep track of most recent packet
650  AVPacket *recent_packet = packet;
651 
652  // Drain any packets from the decoder
653  packet = NULL;
654  int attempts = 0;
655  int max_attempts = 128;
656  while (packet_status.packets_decoded() < packet_status.packets_read() && attempts < max_attempts) {
657  ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::Close (Drain decoder loop)",
658  "packets_read", packet_status.packets_read(),
659  "packets_decoded", packet_status.packets_decoded(),
660  "attempts", attempts);
661  if (packet_status.video_decoded < packet_status.video_read) {
662  ProcessVideoPacket(info.video_length);
663  }
664  if (packet_status.audio_decoded < packet_status.audio_read) {
665  ProcessAudioPacket(info.video_length);
666  }
667  attempts++;
668  }
669 
670  // Remove packet
671  if (recent_packet) {
672  RemoveAVPacket(recent_packet);
673  }
674 
675  // Close the video codec
676  if (info.has_video) {
677  if(avcodec_is_open(pCodecCtx)) {
678  avcodec_flush_buffers(pCodecCtx);
679  }
680  AV_FREE_CONTEXT(pCodecCtx);
681 #if USE_HW_ACCEL
682  if (hw_de_on) {
683  if (hw_device_ctx) {
684  av_buffer_unref(&hw_device_ctx);
685  hw_device_ctx = NULL;
686  }
687  }
688 #endif // USE_HW_ACCEL
689  if (img_convert_ctx) {
690  sws_freeContext(img_convert_ctx);
691  img_convert_ctx = nullptr;
692  }
693  if (pFrameRGB_cached) {
694  AV_FREE_FRAME(&pFrameRGB_cached);
695  }
696  }
697 
698  // Close the audio codec
699  if (info.has_audio) {
700  if(avcodec_is_open(aCodecCtx)) {
701  avcodec_flush_buffers(aCodecCtx);
702  }
703  AV_FREE_CONTEXT(aCodecCtx);
704  if (avr_ctx) {
705  SWR_CLOSE(avr_ctx);
706  SWR_FREE(&avr_ctx);
707  avr_ctx = nullptr;
708  }
709  }
710 
711  // Clear final cache
712  final_cache.Clear();
713  working_cache.Clear();
714 
715  // Close the video file
716  avformat_close_input(&pFormatCtx);
717  av_freep(&pFormatCtx);
718 
719  // Release free’d arenas back to OS after heavy teardown
720  TrimMemoryToOS(true);
721 
722  // Reset some variables
723  last_frame = 0;
724  hold_packet = false;
725  largest_frame_processed = 0;
726  seek_audio_frame_found = 0;
727  seek_video_frame_found = 0;
728  current_video_frame = 0;
729  last_video_frame.reset();
730  }
731 }
732 
733 bool FFmpegReader::HasAlbumArt() {
734  // Check if the video stream we use is an attached picture
735  // This won't return true if the file has a cover image as a secondary stream
736  // like an MKV file with an attached image file
737  return pFormatCtx && videoStream >= 0 && pFormatCtx->streams[videoStream]
738  && (pFormatCtx->streams[videoStream]->disposition & AV_DISPOSITION_ATTACHED_PIC);
739 }
740 
741 double FFmpegReader::PickDurationSeconds() const {
742  auto has_value = [](double value) { return value > 0.0; };
743 
744  switch (duration_strategy) {
746  if (has_value(video_stream_duration_seconds))
747  return video_stream_duration_seconds;
748  if (has_value(audio_stream_duration_seconds))
749  return audio_stream_duration_seconds;
750  if (has_value(format_duration_seconds))
751  return format_duration_seconds;
752  break;
754  if (has_value(audio_stream_duration_seconds))
755  return audio_stream_duration_seconds;
756  if (has_value(video_stream_duration_seconds))
757  return video_stream_duration_seconds;
758  if (has_value(format_duration_seconds))
759  return format_duration_seconds;
760  break;
762  default:
763  {
764  double longest = 0.0;
765  if (has_value(video_stream_duration_seconds))
766  longest = std::max(longest, video_stream_duration_seconds);
767  if (has_value(audio_stream_duration_seconds))
768  longest = std::max(longest, audio_stream_duration_seconds);
769  if (has_value(format_duration_seconds))
770  longest = std::max(longest, format_duration_seconds);
771  if (has_value(longest))
772  return longest;
773  }
774  break;
775  }
776 
777  if (has_value(format_duration_seconds))
778  return format_duration_seconds;
779  if (has_value(inferred_duration_seconds))
780  return inferred_duration_seconds;
781 
782  return 0.0;
783 }
784 
785 void FFmpegReader::ApplyDurationStrategy() {
786  const double fps_value = info.fps.ToDouble();
787  const double chosen_seconds = PickDurationSeconds();
788 
789  if (chosen_seconds <= 0.0 || fps_value <= 0.0) {
790  info.duration = 0.0f;
791  info.video_length = 0;
792  is_duration_known = false;
793  return;
794  }
795 
796  const int64_t frames = static_cast<int64_t>(std::llround(chosen_seconds * fps_value));
797  if (frames <= 0) {
798  info.duration = 0.0f;
799  info.video_length = 0;
800  is_duration_known = false;
801  return;
802  }
803 
804  info.video_length = frames;
805  info.duration = static_cast<float>(static_cast<double>(frames) / fps_value);
806  is_duration_known = true;
807 }
808 
809 void FFmpegReader::UpdateAudioInfo() {
810  // Set default audio channel layout (if needed)
811 #if HAVE_CH_LAYOUT
812  if (!av_channel_layout_check(&(AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->ch_layout)))
813  AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->ch_layout = (AVChannelLayout) AV_CHANNEL_LAYOUT_STEREO;
814 #else
815  if (AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->channel_layout == 0)
816  AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->channel_layout = av_get_default_channel_layout(AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->channels);
817 #endif
818 
819  if (info.sample_rate > 0) {
820  // Skip init - if info struct already populated
821  return;
822  }
823 
824  auto record_duration = [](double &target, double seconds) {
825  if (seconds > 0.0)
826  target = std::max(target, seconds);
827  };
828 
829  // Set values of FileInfo struct
830  info.has_audio = true;
831  info.file_size = pFormatCtx->pb ? avio_size(pFormatCtx->pb) : -1;
832  info.acodec = aCodecCtx->codec->name;
833 #if HAVE_CH_LAYOUT
834  info.channels = AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->ch_layout.nb_channels;
835  info.channel_layout = (ChannelLayout) AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->ch_layout.u.mask;
836 #else
837  info.channels = AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->channels;
838  info.channel_layout = (ChannelLayout) AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->channel_layout;
839 #endif
840 
841  // If channel layout is not set, guess based on the number of channels
842  if (info.channel_layout == 0) {
843  if (info.channels == 1) {
845  } else if (info.channels == 2) {
847  }
848  }
849 
850  info.sample_rate = AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->sample_rate;
851  info.audio_bit_rate = AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->bit_rate;
852  if (info.audio_bit_rate <= 0) {
853  // Get bitrate from format
854  info.audio_bit_rate = pFormatCtx->bit_rate;
855  }
856 
857  // Set audio timebase
858  info.audio_timebase.num = aStream->time_base.num;
859  info.audio_timebase.den = aStream->time_base.den;
860 
861  // Get timebase of audio stream (if valid) and greater than the current duration
862  if (aStream->duration > 0) {
863  record_duration(audio_stream_duration_seconds, aStream->duration * info.audio_timebase.ToDouble());
864  }
865  if (pFormatCtx->duration > 0) {
866  // Use the format's duration when stream duration is missing or shorter
867  record_duration(format_duration_seconds, static_cast<double>(pFormatCtx->duration) / AV_TIME_BASE);
868  }
869 
870  // Calculate duration from filesize and bitrate (if any)
871  if (info.duration <= 0.0f && info.video_bit_rate > 0 && info.file_size > 0) {
872  // Estimate from bitrate, total bytes, and framerate
873  record_duration(inferred_duration_seconds, static_cast<double>(info.file_size) / info.video_bit_rate);
874  }
875 
876  // Set video timebase (if no video stream was found)
877  if (!info.has_video) {
878  // Set a few important default video settings (so audio can be divided into frames)
879  info.fps.num = 30;
880  info.fps.den = 1;
881  info.video_timebase.num = 1;
882  info.video_timebase.den = 30;
883  info.width = 720;
884  info.height = 480;
885 
886  // Use timeline to set correct width & height (if any)
887  Clip *parent = static_cast<Clip *>(ParentClip());
888  if (parent) {
889  if (parent->ParentTimeline()) {
890  // Set max width/height based on parent clip's timeline (if attached to a timeline)
891  info.width = parent->ParentTimeline()->preview_width;
892  info.height = parent->ParentTimeline()->preview_height;
893  }
894  }
895  }
896 
897  ApplyDurationStrategy();
898 
899  // Add audio metadata (if any found)
900  AVDictionaryEntry *tag = NULL;
901  while ((tag = av_dict_get(aStream->metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) {
902  QString str_key = tag->key;
903  QString str_value = tag->value;
904  info.metadata[str_key.toStdString()] = str_value.trimmed().toStdString();
905  }
906 }
907 
908 void FFmpegReader::UpdateVideoInfo() {
909  if (info.vcodec.length() > 0) {
910  // Skip init - if info struct already populated
911  return;
912  }
913 
914  auto record_duration = [](double &target, double seconds) {
915  if (seconds > 0.0)
916  target = std::max(target, seconds);
917  };
918 
919  // Set values of FileInfo struct
920  info.has_video = true;
921  info.file_size = pFormatCtx->pb ? avio_size(pFormatCtx->pb) : -1;
922  info.height = AV_GET_CODEC_ATTRIBUTES(pStream, pCodecCtx)->height;
923  info.width = AV_GET_CODEC_ATTRIBUTES(pStream, pCodecCtx)->width;
924  info.vcodec = pCodecCtx->codec->name;
925  info.video_bit_rate = (pFormatCtx->bit_rate / 8);
926 
927  // Frame rate from the container and codec
928  AVRational framerate = av_guess_frame_rate(pFormatCtx, pStream, NULL);
929  if (!check_fps) {
930  info.fps.num = framerate.num;
931  info.fps.den = framerate.den;
932  }
933 
934  ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::UpdateVideoInfo", "info.fps.num", info.fps.num, "info.fps.den", info.fps.den);
935 
936  // TODO: remove excessive debug info in the next releases
937  // The debug info below is just for comparison and troubleshooting on users side during the transition period
938  ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::UpdateVideoInfo (pStream->avg_frame_rate)", "num", pStream->avg_frame_rate.num, "den", pStream->avg_frame_rate.den);
939 
940  if (pStream->sample_aspect_ratio.num != 0) {
941  info.pixel_ratio.num = pStream->sample_aspect_ratio.num;
942  info.pixel_ratio.den = pStream->sample_aspect_ratio.den;
943  } else if (AV_GET_CODEC_ATTRIBUTES(pStream, pCodecCtx)->sample_aspect_ratio.num != 0) {
944  info.pixel_ratio.num = AV_GET_CODEC_ATTRIBUTES(pStream, pCodecCtx)->sample_aspect_ratio.num;
945  info.pixel_ratio.den = AV_GET_CODEC_ATTRIBUTES(pStream, pCodecCtx)->sample_aspect_ratio.den;
946  } else {
947  info.pixel_ratio.num = 1;
948  info.pixel_ratio.den = 1;
949  }
950  info.pixel_format = AV_GET_CODEC_PIXEL_FORMAT(pStream, pCodecCtx);
951 
952  // Calculate the DAR (display aspect ratio)
954 
955  // Reduce size fraction
956  size.Reduce();
957 
958  // Set the ratio based on the reduced fraction
959  info.display_ratio.num = size.num;
960  info.display_ratio.den = size.den;
961 
962  // Get scan type and order from codec context/params
963  if (!check_interlace) {
964  check_interlace = true;
965  AVFieldOrder field_order = AV_GET_CODEC_ATTRIBUTES(pStream, pCodecCtx)->field_order;
966  switch(field_order) {
967  case AV_FIELD_PROGRESSIVE:
968  info.interlaced_frame = false;
969  break;
970  case AV_FIELD_TT:
971  case AV_FIELD_TB:
972  info.interlaced_frame = true;
973  info.top_field_first = true;
974  break;
975  case AV_FIELD_BT:
976  case AV_FIELD_BB:
977  info.interlaced_frame = true;
978  info.top_field_first = false;
979  break;
980  case AV_FIELD_UNKNOWN:
981  // Check again later?
982  check_interlace = false;
983  break;
984  }
985  // check_interlace will prevent these checks being repeated,
986  // unless it was cleared because we got an AV_FIELD_UNKNOWN response.
987  }
988 
989  // Set the video timebase
990  info.video_timebase.num = pStream->time_base.num;
991  info.video_timebase.den = pStream->time_base.den;
992 
993  // Set the duration in seconds, and video length (# of frames)
994  record_duration(video_stream_duration_seconds, pStream->duration * info.video_timebase.ToDouble());
995 
996  // Check for valid duration (if found)
997  if (pFormatCtx->duration >= 0) {
998  // Use the format's duration as another candidate
999  record_duration(format_duration_seconds, static_cast<double>(pFormatCtx->duration) / AV_TIME_BASE);
1000  }
1001 
1002  // Calculate duration from filesize and bitrate (if any)
1003  if (info.video_bit_rate > 0 && info.file_size > 0) {
1004  // Estimate from bitrate, total bytes, and framerate
1005  record_duration(inferred_duration_seconds, static_cast<double>(info.file_size) / info.video_bit_rate);
1006  }
1007 
1008  // Certain "image" formats do not have a valid duration
1009  if (video_stream_duration_seconds <= 0.0 && format_duration_seconds <= 0.0 &&
1010  pStream->duration == AV_NOPTS_VALUE && pFormatCtx->duration == AV_NOPTS_VALUE) {
1011  // Force an "image" duration
1012  record_duration(video_stream_duration_seconds, 60 * 60 * 1); // 1 hour duration
1013  info.has_single_image = true;
1014  }
1015  // Static GIFs can have no usable duration; fall back to a small default
1016  if (video_stream_duration_seconds <= 0.0 && format_duration_seconds <= 0.0 &&
1017  pFormatCtx && pFormatCtx->iformat && strcmp(pFormatCtx->iformat->name, "gif") == 0) {
1018  record_duration(video_stream_duration_seconds, 60 * 60 * 1); // 1 hour duration
1019  info.has_single_image = true;
1020  }
1021 
1022  ApplyDurationStrategy();
1023 
1024  // Add video metadata (if any)
1025  AVDictionaryEntry *tag = NULL;
1026  while ((tag = av_dict_get(pStream->metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) {
1027  QString str_key = tag->key;
1028  QString str_value = tag->value;
1029  info.metadata[str_key.toStdString()] = str_value.trimmed().toStdString();
1030  }
1031 }
1032 
1034  return this->is_duration_known;
1035 }
1036 
1037 std::shared_ptr<Frame> FFmpegReader::GetFrame(int64_t requested_frame) {
1038  // Check for open reader (or throw exception)
1039  if (!is_open)
1040  throw ReaderClosed("The FFmpegReader is closed. Call Open() before calling this method.", path);
1041 
1042  // Adjust for a requested frame that is too small or too large
1043  if (requested_frame < 1)
1044  requested_frame = 1;
1045  if (requested_frame > info.video_length && is_duration_known)
1046  requested_frame = info.video_length;
1047  if (info.has_video && info.video_length == 0)
1048  // Invalid duration of video file
1049  throw InvalidFile("Could not detect the duration of the video or audio stream.", path);
1050 
1051  // Debug output
1052  ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::GetFrame", "requested_frame", requested_frame, "last_frame", last_frame);
1053 
1054  // Check the cache for this frame
1055  std::shared_ptr<Frame> frame = final_cache.GetFrame(requested_frame);
1056  if (frame) {
1057  // Debug output
1058  ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::GetFrame", "returned cached frame", requested_frame);
1059 
1060  // Return the cached frame
1061  return frame;
1062  } else {
1063 
1064  // Prevent async calls to the remainder of this code
1065  const std::lock_guard<std::recursive_mutex> lock(getFrameMutex);
1066 
1067  // Check the cache a 2nd time (due to the potential previous lock)
1068  frame = final_cache.GetFrame(requested_frame);
1069  if (frame) {
1070  // Debug output
1071  ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::GetFrame", "returned cached frame on 2nd look", requested_frame);
1072 
1073  } else {
1074  // Frame is not in cache
1075  // Reset seek count
1076  seek_count = 0;
1077 
1078  // Are we within X frames of the requested frame?
1079  int64_t diff = requested_frame - last_frame;
1080  if (diff >= 1 && diff <= 20) {
1081  // Continue walking the stream
1082  frame = ReadStream(requested_frame);
1083  } else {
1084  // Greater than 30 frames away, or backwards, we need to seek to the nearest key frame
1085  if (enable_seek) {
1086  // Only seek if enabled
1087  Seek(requested_frame);
1088 
1089  } else if (!enable_seek && diff < 0) {
1090  // Start over, since we can't seek, and the requested frame is smaller than our position
1091  // Since we are seeking to frame 1, this actually just closes/re-opens the reader
1092  Seek(1);
1093  }
1094 
1095  // Then continue walking the stream
1096  frame = ReadStream(requested_frame);
1097  }
1098  }
1099  return frame;
1100  }
1101 }
1102 
1103 // Read the stream until we find the requested Frame
1104 std::shared_ptr<Frame> FFmpegReader::ReadStream(int64_t requested_frame) {
1105  // Allocate video frame
1106  bool check_seek = false;
1107  int packet_error = -1;
1108 
1109  // Debug output
1110  ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ReadStream", "requested_frame", requested_frame);
1111 
1112  // Loop through the stream until the correct frame is found
1113  while (true) {
1114  // Check if working frames are 'finished'
1115  if (!is_seeking) {
1116  // Check for final frames
1117  CheckWorkingFrames(requested_frame);
1118  }
1119 
1120  // Check if requested 'final' frame is available (and break out of loop if found)
1121  bool is_cache_found = (final_cache.GetFrame(requested_frame) != NULL);
1122  if (is_cache_found) {
1123  break;
1124  }
1125 
1126  if (!hold_packet || !packet) {
1127  // Get the next packet
1128  packet_error = GetNextPacket();
1129  if (packet_error < 0 && !packet) {
1130  // No more packets to be found
1131  packet_status.packets_eof = true;
1132  }
1133  }
1134 
1135  // Debug output
1136  ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ReadStream (GetNextPacket)", "requested_frame", requested_frame,"packets_read", packet_status.packets_read(), "packets_decoded", packet_status.packets_decoded(), "is_seeking", is_seeking);
1137 
1138  // Check the status of a seek (if any)
1139  if (is_seeking) {
1140  check_seek = CheckSeek(false);
1141  } else {
1142  check_seek = false;
1143  }
1144 
1145  if (check_seek) {
1146  // Packet may become NULL on Close inside Seek if CheckSeek returns false
1147  // Jump to the next iteration of this loop
1148  continue;
1149  }
1150 
1151  // Video packet
1152  if ((info.has_video && packet && packet->stream_index == videoStream) ||
1153  (info.has_video && packet_status.video_decoded < packet_status.video_read) ||
1154  (info.has_video && !packet && !packet_status.video_eof)) {
1155  // Process Video Packet
1156  ProcessVideoPacket(requested_frame);
1157  }
1158  // Audio packet
1159  if ((info.has_audio && packet && packet->stream_index == audioStream) ||
1160  (info.has_audio && !packet && packet_status.audio_decoded < packet_status.audio_read) ||
1161  (info.has_audio && !packet && !packet_status.audio_eof)) {
1162  // Process Audio Packet
1163  ProcessAudioPacket(requested_frame);
1164  }
1165 
1166  // Remove unused packets (sometimes we purposely ignore video or audio packets,
1167  // if the has_video or has_audio properties are manually overridden)
1168  if ((!info.has_video && packet && packet->stream_index == videoStream) ||
1169  (!info.has_audio && packet && packet->stream_index == audioStream)) {
1170  // Keep track of deleted packet counts
1171  if (packet->stream_index == videoStream) {
1172  packet_status.video_decoded++;
1173  } else if (packet->stream_index == audioStream) {
1174  packet_status.audio_decoded++;
1175  }
1176 
1177  // Remove unused packets (sometimes we purposely ignore video or audio packets,
1178  // if the has_video or has_audio properties are manually overridden)
1179  RemoveAVPacket(packet);
1180  packet = NULL;
1181  }
1182 
1183  // Determine end-of-stream (waiting until final decoder threads finish)
1184  // Force end-of-stream in some situations
1185  packet_status.end_of_file = packet_status.packets_eof && packet_status.video_eof && packet_status.audio_eof;
1186  if ((packet_status.packets_eof && packet_status.packets_read() == packet_status.packets_decoded()) || packet_status.end_of_file) {
1187  // Force EOF (end of file) variables to true, if decoder does not support EOF detection.
1188  // If we have no more packets, and all known packets have been decoded
1189  ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ReadStream (force EOF)", "packets_read", packet_status.packets_read(), "packets_decoded", packet_status.packets_decoded(), "packets_eof", packet_status.packets_eof, "video_eof", packet_status.video_eof, "audio_eof", packet_status.audio_eof, "end_of_file", packet_status.end_of_file);
1190  if (!packet_status.video_eof) {
1191  packet_status.video_eof = true;
1192  }
1193  if (!packet_status.audio_eof) {
1194  packet_status.audio_eof = true;
1195  }
1196  packet_status.end_of_file = true;
1197  break;
1198  }
1199  } // end while
1200 
1201  // Debug output
1202  ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ReadStream (Completed)",
1203  "packets_read", packet_status.packets_read(),
1204  "packets_decoded", packet_status.packets_decoded(),
1205  "end_of_file", packet_status.end_of_file,
1206  "largest_frame_processed", largest_frame_processed,
1207  "Working Cache Count", working_cache.Count());
1208 
1209  // Have we reached end-of-stream (or the final frame)?
1210  if (!packet_status.end_of_file && requested_frame >= info.video_length) {
1211  // Force end-of-stream
1212  packet_status.end_of_file = true;
1213  }
1214  if (packet_status.end_of_file) {
1215  // Mark any other working frames as 'finished'
1216  CheckWorkingFrames(requested_frame);
1217  }
1218 
1219  // Return requested frame (if found)
1220  std::shared_ptr<Frame> frame = final_cache.GetFrame(requested_frame);
1221  if (frame)
1222  // Return prepared frame
1223  return frame;
1224  else {
1225 
1226  // Check if largest frame is still cached
1227  frame = final_cache.GetFrame(largest_frame_processed);
1228  int samples_in_frame = Frame::GetSamplesPerFrame(requested_frame, info.fps,
1230  if (frame) {
1231  // Copy and return the largest processed frame (assuming it was the last in the video file)
1232  std::shared_ptr<Frame> f = CreateFrame(largest_frame_processed);
1233 
1234  // Use solid color (if no image data found)
1235  if (!frame->has_image_data) {
1236  // Use solid black frame if no image data available
1237  f->AddColor(info.width, info.height, "#000");
1238  }
1239  // Silence audio data (if any), since we are repeating the last frame
1240  frame->AddAudioSilence(samples_in_frame);
1241 
1242  return frame;
1243  } else {
1244  // The largest processed frame is no longer in cache, return a blank frame
1245  std::shared_ptr<Frame> f = CreateFrame(largest_frame_processed);
1246  f->AddColor(info.width, info.height, "#000");
1247  f->AddAudioSilence(samples_in_frame);
1248  return f;
1249  }
1250  }
1251 
1252 }
1253 
1254 // Get the next packet (if any)
1255 int FFmpegReader::GetNextPacket() {
1256  int found_packet = 0;
1257  AVPacket *next_packet;
1258  next_packet = new AVPacket();
1259  found_packet = av_read_frame(pFormatCtx, next_packet);
1260 
1261  if (packet) {
1262  // Remove previous packet before getting next one
1263  RemoveAVPacket(packet);
1264  packet = NULL;
1265  }
1266  if (found_packet >= 0) {
1267  // Update current packet pointer
1268  packet = next_packet;
1269 
1270  // Keep track of packet stats
1271  if (packet->stream_index == videoStream) {
1272  packet_status.video_read++;
1273  } else if (packet->stream_index == audioStream) {
1274  packet_status.audio_read++;
1275  }
1276  } else {
1277  // No more packets found
1278  delete next_packet;
1279  packet = NULL;
1280  }
1281  // Return if packet was found (or error number)
1282  return found_packet;
1283 }
1284 
1285 // Get an AVFrame (if any)
1286 bool FFmpegReader::GetAVFrame() {
1287  int frameFinished = 0;
1288 
1289  // Decode video frame
1290  AVFrame *next_frame = AV_ALLOCATE_FRAME();
1291 
1292 #if IS_FFMPEG_3_2
1293  int send_packet_err = 0;
1294  int64_t send_packet_pts = 0;
1295  if ((packet && packet->stream_index == videoStream) || !packet) {
1296  send_packet_err = avcodec_send_packet(pCodecCtx, packet);
1297 
1298  if (packet && send_packet_err >= 0) {
1299  send_packet_pts = GetPacketPTS();
1300  hold_packet = false;
1301  ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::GetAVFrame (send packet succeeded)", "send_packet_err", send_packet_err, "send_packet_pts", send_packet_pts);
1302  }
1303  }
1304 
1305  #if USE_HW_ACCEL
1306  // Get the format from the variables set in get_hw_dec_format
1307  hw_de_av_pix_fmt = hw_de_av_pix_fmt_global;
1308  hw_de_av_device_type = hw_de_av_device_type_global;
1309  #endif // USE_HW_ACCEL
1310  if (send_packet_err < 0 && send_packet_err != AVERROR_EOF) {
1311  ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::GetAVFrame (send packet: Not sent [" + av_err2string(send_packet_err) + "])", "send_packet_err", send_packet_err, "send_packet_pts", send_packet_pts);
1312  if (send_packet_err == AVERROR(EAGAIN)) {
1313  hold_packet = true;
1314  ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::GetAVFrame (send packet: AVERROR(EAGAIN): user must read output with avcodec_receive_frame()", "send_packet_pts", send_packet_pts);
1315  }
1316  if (send_packet_err == AVERROR(EINVAL)) {
1317  ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::GetAVFrame (send packet: AVERROR(EINVAL): codec not opened, it is an encoder, or requires flush", "send_packet_pts", send_packet_pts);
1318  }
1319  if (send_packet_err == AVERROR(ENOMEM)) {
1320  ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::GetAVFrame (send packet: AVERROR(ENOMEM): failed to add packet to internal queue, or legitimate decoding errors", "send_packet_pts", send_packet_pts);
1321  }
1322  }
1323 
1324  // Always try and receive a packet, if not EOF.
1325  // Even if the above avcodec_send_packet failed to send,
1326  // we might still need to receive a packet.
1327  int receive_frame_err = 0;
1328  AVFrame *next_frame2;
1329 #if USE_HW_ACCEL
1330  if (hw_de_on && hw_de_supported) {
1331  next_frame2 = AV_ALLOCATE_FRAME();
1332  }
1333  else
1334 #endif // USE_HW_ACCEL
1335  {
1336  next_frame2 = next_frame;
1337  }
1338  pFrame = AV_ALLOCATE_FRAME();
1339  while (receive_frame_err >= 0) {
1340  receive_frame_err = avcodec_receive_frame(pCodecCtx, next_frame2);
1341 
1342  if (receive_frame_err != 0) {
1343  ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::GetAVFrame (receive frame: frame not ready yet from decoder [\" + av_err2string(receive_frame_err) + \"])", "receive_frame_err", receive_frame_err, "send_packet_pts", send_packet_pts);
1344 
1345  if (receive_frame_err == AVERROR_EOF) {
1347  "FFmpegReader::GetAVFrame (receive frame: AVERROR_EOF: EOF detected from decoder, flushing buffers)", "send_packet_pts", send_packet_pts);
1348  avcodec_flush_buffers(pCodecCtx);
1349  packet_status.video_eof = true;
1350  }
1351  if (receive_frame_err == AVERROR(EINVAL)) {
1353  "FFmpegReader::GetAVFrame (receive frame: AVERROR(EINVAL): invalid frame received, flushing buffers)", "send_packet_pts", send_packet_pts);
1354  avcodec_flush_buffers(pCodecCtx);
1355  }
1356  if (receive_frame_err == AVERROR(EAGAIN)) {
1358  "FFmpegReader::GetAVFrame (receive frame: AVERROR(EAGAIN): output is not available in this state - user must try to send new input)", "send_packet_pts", send_packet_pts);
1359  }
1360  if (receive_frame_err == AVERROR_INPUT_CHANGED) {
1362  "FFmpegReader::GetAVFrame (receive frame: AVERROR_INPUT_CHANGED: current decoded frame has changed parameters with respect to first decoded frame)", "send_packet_pts", send_packet_pts);
1363  }
1364 
1365  // Break out of decoding loop
1366  // Nothing ready for decoding yet
1367  break;
1368  }
1369 
1370 #if USE_HW_ACCEL
1371  if (hw_de_on && hw_de_supported) {
1372  int err;
1373  if (next_frame2->format == hw_de_av_pix_fmt) {
1374  next_frame->format = AV_PIX_FMT_YUV420P;
1375  if ((err = av_hwframe_transfer_data(next_frame,next_frame2,0)) < 0) {
1376  ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::GetAVFrame (Failed to transfer data to output frame)", "hw_de_on", hw_de_on);
1377  }
1378  if ((err = av_frame_copy_props(next_frame,next_frame2)) < 0) {
1379  ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::GetAVFrame (Failed to copy props to output frame)", "hw_de_on", hw_de_on);
1380  }
1381  }
1382  }
1383  else
1384 #endif // USE_HW_ACCEL
1385  { // No hardware acceleration used -> no copy from GPU memory needed
1386  next_frame = next_frame2;
1387  }
1388 
1389  // TODO also handle possible further frames
1390  // Use only the first frame like avcodec_decode_video2
1391  frameFinished = 1;
1392  packet_status.video_decoded++;
1393 
1394  // Allocate image (align 32 for simd)
1395  if (AV_ALLOCATE_IMAGE(pFrame, (AVPixelFormat)(pStream->codecpar->format), info.width, info.height) <= 0) {
1396  throw OutOfMemory("Failed to allocate image buffer", path);
1397  }
1398  av_image_copy(pFrame->data, pFrame->linesize, (const uint8_t**)next_frame->data, next_frame->linesize,
1399  (AVPixelFormat)(pStream->codecpar->format), info.width, info.height);
1400 
1401  // Get display PTS from video frame, often different than packet->pts.
1402  // Sending packets to the decoder (i.e. packet->pts) is async,
1403  // and retrieving packets from the decoder (frame->pts) is async. In most decoders
1404  // sending and retrieving are separated by multiple calls to this method.
1405  if (next_frame->pts != AV_NOPTS_VALUE) {
1406  // This is the current decoded frame (and should be the pts used) for
1407  // processing this data
1408  video_pts = next_frame->pts;
1409  } else if (next_frame->pkt_dts != AV_NOPTS_VALUE) {
1410  // Some videos only set this timestamp (fallback)
1411  video_pts = next_frame->pkt_dts;
1412  }
1413 
1415  "FFmpegReader::GetAVFrame (Successful frame received)", "video_pts", video_pts, "send_packet_pts", send_packet_pts);
1416 
1417  // break out of loop after each successful image returned
1418  break;
1419  }
1420 #if USE_HW_ACCEL
1421  if (hw_de_on && hw_de_supported) {
1422  AV_FREE_FRAME(&next_frame2);
1423  }
1424  #endif // USE_HW_ACCEL
1425 #else
1426  avcodec_decode_video2(pCodecCtx, next_frame, &frameFinished, packet);
1427 
1428  // always allocate pFrame (because we do that in the ffmpeg >= 3.2 as well); it will always be freed later
1429  pFrame = AV_ALLOCATE_FRAME();
1430 
1431  // is frame finished
1432  if (frameFinished) {
1433  // AVFrames are clobbered on the each call to avcodec_decode_video, so we
1434  // must make a copy of the image data before this method is called again.
1435  avpicture_alloc((AVPicture *) pFrame, pCodecCtx->pix_fmt, info.width, info.height);
1436  av_picture_copy((AVPicture *) pFrame, (AVPicture *) next_frame, pCodecCtx->pix_fmt, info.width,
1437  info.height);
1438  }
1439 #endif // IS_FFMPEG_3_2
1440 
1441  // deallocate the frame
1442  AV_FREE_FRAME(&next_frame);
1443 
1444  // Did we get a video frame?
1445  return frameFinished;
1446 }
1447 
1448 // Check the current seek position and determine if we need to seek again
1449 bool FFmpegReader::CheckSeek(bool is_video) {
1450  // Are we seeking for a specific frame?
1451  if (is_seeking) {
1452  // Determine if both an audio and video packet have been decoded since the seek happened.
1453  // If not, allow the ReadStream method to keep looping
1454  if ((is_video_seek && !seek_video_frame_found) || (!is_video_seek && !seek_audio_frame_found))
1455  return false;
1456 
1457  // Check for both streams
1458  if ((info.has_video && !seek_video_frame_found) || (info.has_audio && !seek_audio_frame_found))
1459  return false;
1460 
1461  // Determine max seeked frame
1462  int64_t max_seeked_frame = std::max(seek_audio_frame_found, seek_video_frame_found);
1463 
1464  // determine if we are "before" the requested frame
1465  if (max_seeked_frame >= seeking_frame) {
1466  // SEEKED TOO FAR
1467  ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::CheckSeek (Too far, seek again)",
1468  "is_video_seek", is_video_seek,
1469  "max_seeked_frame", max_seeked_frame,
1470  "seeking_frame", seeking_frame,
1471  "seeking_pts", seeking_pts,
1472  "seek_video_frame_found", seek_video_frame_found,
1473  "seek_audio_frame_found", seek_audio_frame_found);
1474 
1475  // Seek again... to the nearest Keyframe
1476  Seek(seeking_frame - (10 * seek_count * seek_count));
1477  } else {
1478  // SEEK WORKED
1479  ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::CheckSeek (Successful)",
1480  "is_video_seek", is_video_seek,
1481  "packet->pts", GetPacketPTS(),
1482  "seeking_pts", seeking_pts,
1483  "seeking_frame", seeking_frame,
1484  "seek_video_frame_found", seek_video_frame_found,
1485  "seek_audio_frame_found", seek_audio_frame_found);
1486 
1487  // Seek worked, and we are "before" the requested frame
1488  is_seeking = false;
1489  seeking_frame = 0;
1490  seeking_pts = -1;
1491  }
1492  }
1493 
1494  // return the pts to seek to (if any)
1495  return is_seeking;
1496 }
1497 
1498 // Process a video packet
1499 void FFmpegReader::ProcessVideoPacket(int64_t requested_frame) {
1500  // Get the AVFrame from the current packet
1501  // This sets the video_pts to the correct timestamp
1502  int frame_finished = GetAVFrame();
1503 
1504  // Check if the AVFrame is finished and set it
1505  if (!frame_finished) {
1506  // No AVFrame decoded yet, bail out
1507  if (pFrame) {
1508  RemoveAVFrame(pFrame);
1509  }
1510  return;
1511  }
1512 
1513  // Calculate current frame #
1514  int64_t current_frame = ConvertVideoPTStoFrame(video_pts);
1515 
1516  // Track 1st video packet after a successful seek
1517  if (!seek_video_frame_found && is_seeking)
1518  seek_video_frame_found = current_frame;
1519 
1520  // Create or get the existing frame object. Requested frame needs to be created
1521  // in working_cache at least once. Seek can clear the working_cache, so we must
1522  // add the requested frame back to the working_cache here. If it already exists,
1523  // it will be moved to the top of the working_cache.
1524  working_cache.Add(CreateFrame(requested_frame));
1525 
1526  // Debug output
1527  ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ProcessVideoPacket (Before)", "requested_frame", requested_frame, "current_frame", current_frame);
1528 
1529  // Init some things local (for OpenMP)
1530  PixelFormat pix_fmt = AV_GET_CODEC_PIXEL_FORMAT(pStream, pCodecCtx);
1531  int height = info.height;
1532  int width = info.width;
1533  int64_t video_length = info.video_length;
1534 
1535  // Create or reuse a RGB Frame (since most videos are not in RGB, we must convert it)
1536  AVFrame *pFrameRGB = pFrameRGB_cached;
1537  if (!pFrameRGB) {
1538  pFrameRGB = AV_ALLOCATE_FRAME();
1539  if (pFrameRGB == nullptr)
1540  throw OutOfMemory("Failed to allocate frame buffer", path);
1541  pFrameRGB_cached = pFrameRGB;
1542  }
1543  AV_RESET_FRAME(pFrameRGB);
1544  uint8_t *buffer = nullptr;
1545 
1546  // Determine the max size of this source image (based on the timeline's size, the scaling mode,
1547  // and the scaling keyframes). This is a performance improvement, to keep the images as small as possible,
1548  // without losing quality. NOTE: We cannot go smaller than the timeline itself, or the add_layer timeline
1549  // method will scale it back to timeline size before scaling it smaller again. This needs to be fixed in
1550  // the future.
1551  int max_width = info.width;
1552  int max_height = info.height;
1553 
1554  Clip *parent = static_cast<Clip *>(ParentClip());
1555  if (parent) {
1556  if (parent->ParentTimeline()) {
1557  // Set max width/height based on parent clip's timeline (if attached to a timeline)
1558  max_width = parent->ParentTimeline()->preview_width;
1559  max_height = parent->ParentTimeline()->preview_height;
1560  }
1561  if (parent->scale == SCALE_FIT || parent->scale == SCALE_STRETCH) {
1562  // Best fit or Stretch scaling (based on max timeline size * scaling keyframes)
1563  float max_scale_x = parent->scale_x.GetMaxPoint().co.Y;
1564  float max_scale_y = parent->scale_y.GetMaxPoint().co.Y;
1565  max_width = std::max(float(max_width), max_width * max_scale_x);
1566  max_height = std::max(float(max_height), max_height * max_scale_y);
1567 
1568  } else if (parent->scale == SCALE_CROP) {
1569  // Cropping scale mode (based on max timeline size * cropped size * scaling keyframes)
1570  float max_scale_x = parent->scale_x.GetMaxPoint().co.Y;
1571  float max_scale_y = parent->scale_y.GetMaxPoint().co.Y;
1572  QSize width_size(max_width * max_scale_x,
1573  round(max_width / (float(info.width) / float(info.height))));
1574  QSize height_size(round(max_height / (float(info.height) / float(info.width))),
1575  max_height * max_scale_y);
1576  // respect aspect ratio
1577  if (width_size.width() >= max_width && width_size.height() >= max_height) {
1578  max_width = std::max(max_width, width_size.width());
1579  max_height = std::max(max_height, width_size.height());
1580  } else {
1581  max_width = std::max(max_width, height_size.width());
1582  max_height = std::max(max_height, height_size.height());
1583  }
1584 
1585  } else {
1586  // Scale video to equivalent unscaled size
1587  // Since the preview window can change sizes, we want to always
1588  // scale against the ratio of original video size to timeline size
1589  float preview_ratio = 1.0;
1590  if (parent->ParentTimeline()) {
1591  Timeline *t = (Timeline *) parent->ParentTimeline();
1592  preview_ratio = t->preview_width / float(t->info.width);
1593  }
1594  float max_scale_x = parent->scale_x.GetMaxPoint().co.Y;
1595  float max_scale_y = parent->scale_y.GetMaxPoint().co.Y;
1596  max_width = info.width * max_scale_x * preview_ratio;
1597  max_height = info.height * max_scale_y * preview_ratio;
1598  }
1599 
1600  // If a crop effect is resizing the image, request enough pixels to preserve detail
1601  ApplyCropResizeScale(parent, info.width, info.height, max_width, max_height);
1602  }
1603 
1604  // Determine if image needs to be scaled (for performance reasons)
1605  int original_height = height;
1606  if (max_width != 0 && max_height != 0 && max_width < width && max_height < height) {
1607  // Override width and height (but maintain aspect ratio)
1608  float ratio = float(width) / float(height);
1609  int possible_width = round(max_height * ratio);
1610  int possible_height = round(max_width / ratio);
1611 
1612  if (possible_width <= max_width) {
1613  // use calculated width, and max_height
1614  width = possible_width;
1615  height = max_height;
1616  } else {
1617  // use max_width, and calculated height
1618  width = max_width;
1619  height = possible_height;
1620  }
1621  }
1622 
1623  // Determine required buffer size and allocate buffer
1624  const int bytes_per_pixel = 4;
1625  int raw_buffer_size = (width * height * bytes_per_pixel) + 128;
1626 
1627  // Aligned memory allocation (for speed)
1628  constexpr size_t ALIGNMENT = 32; // AVX2
1629  int buffer_size = ((raw_buffer_size + ALIGNMENT - 1) / ALIGNMENT) * ALIGNMENT;
1630  buffer = (unsigned char*) aligned_malloc(buffer_size, ALIGNMENT);
1631 
1632  // Copy picture data from one AVFrame (or AVPicture) to another one.
1633  AV_COPY_PICTURE_DATA(pFrameRGB, buffer, PIX_FMT_RGBA, width, height);
1634 
1635  int scale_mode = SWS_FAST_BILINEAR;
1636  if (openshot::Settings::Instance()->HIGH_QUALITY_SCALING) {
1637  scale_mode = SWS_BICUBIC;
1638  }
1639  img_convert_ctx = sws_getCachedContext(img_convert_ctx, info.width, info.height, AV_GET_CODEC_PIXEL_FORMAT(pStream, pCodecCtx), width, height, PIX_FMT_RGBA, scale_mode, NULL, NULL, NULL);
1640  if (!img_convert_ctx)
1641  throw OutOfMemory("Failed to initialize sws context", path);
1642 
1643  // Resize / Convert to RGB
1644  sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize, 0,
1645  original_height, pFrameRGB->data, pFrameRGB->linesize);
1646 
1647  // Create or get the existing frame object
1648  std::shared_ptr<Frame> f = CreateFrame(current_frame);
1649 
1650  // Add Image data to frame
1651  if (!ffmpeg_has_alpha(AV_GET_CODEC_PIXEL_FORMAT(pStream, pCodecCtx))) {
1652  // Add image with no alpha channel, Speed optimization
1653  f->AddImage(width, height, bytes_per_pixel, QImage::Format_RGBA8888_Premultiplied, buffer);
1654  } else {
1655  // Add image with alpha channel (this will be converted to premultipled when needed, but is slower)
1656  f->AddImage(width, height, bytes_per_pixel, QImage::Format_RGBA8888, buffer);
1657  }
1658 
1659  // Update working cache
1660  working_cache.Add(f);
1661 
1662  // Keep track of last last_video_frame
1663  last_video_frame = f;
1664 
1665  // Free the RGB image
1666  AV_RESET_FRAME(pFrameRGB);
1667 
1668  // Remove frame and packet
1669  RemoveAVFrame(pFrame);
1670 
1671  // Get video PTS in seconds
1672  video_pts_seconds = (double(video_pts) * info.video_timebase.ToDouble()) + pts_offset_seconds;
1673 
1674  // Debug output
1675  ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ProcessVideoPacket (After)", "requested_frame", requested_frame, "current_frame", current_frame, "f->number", f->number, "video_pts_seconds", video_pts_seconds);
1676 }
1677 
1678 // Process an audio packet
1679 void FFmpegReader::ProcessAudioPacket(int64_t requested_frame) {
1680  AudioLocation location;
1681  // Calculate location of current audio packet
1682  if (packet && packet->pts != AV_NOPTS_VALUE) {
1683  // Determine related video frame and starting sample # from audio PTS
1684  location = GetAudioPTSLocation(packet->pts);
1685 
1686  // Track 1st audio packet after a successful seek
1687  if (!seek_audio_frame_found && is_seeking)
1688  seek_audio_frame_found = location.frame;
1689  }
1690 
1691  // Create or get the existing frame object. Requested frame needs to be created
1692  // in working_cache at least once. Seek can clear the working_cache, so we must
1693  // add the requested frame back to the working_cache here. If it already exists,
1694  // it will be moved to the top of the working_cache.
1695  working_cache.Add(CreateFrame(requested_frame));
1696 
1697  // Debug output
1698  ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ProcessAudioPacket (Before)",
1699  "requested_frame", requested_frame,
1700  "target_frame", location.frame,
1701  "starting_sample", location.sample_start);
1702 
1703  // Init an AVFrame to hold the decoded audio samples
1704  int frame_finished = 0;
1705  AVFrame *audio_frame = AV_ALLOCATE_FRAME();
1706  AV_RESET_FRAME(audio_frame);
1707 
1708  int packet_samples = 0;
1709  int data_size = 0;
1710 
1711 #if IS_FFMPEG_3_2
1712  int send_packet_err = avcodec_send_packet(aCodecCtx, packet);
1713  if (send_packet_err < 0 && send_packet_err != AVERROR_EOF) {
1714  ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ProcessAudioPacket (Packet not sent)");
1715  }
1716  else {
1717  int receive_frame_err = avcodec_receive_frame(aCodecCtx, audio_frame);
1718  if (receive_frame_err >= 0) {
1719  frame_finished = 1;
1720  }
1721  if (receive_frame_err == AVERROR_EOF) {
1722  ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ProcessAudioPacket (EOF detected from decoder)");
1723  packet_status.audio_eof = true;
1724  }
1725  if (receive_frame_err == AVERROR(EINVAL) || receive_frame_err == AVERROR_EOF) {
1726  ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ProcessAudioPacket (invalid frame received or EOF from decoder)");
1727  avcodec_flush_buffers(aCodecCtx);
1728  }
1729  if (receive_frame_err != 0) {
1730  ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ProcessAudioPacket (frame not ready yet from decoder)");
1731  }
1732  }
1733 #else
1734  int used = avcodec_decode_audio4(aCodecCtx, audio_frame, &frame_finished, packet);
1735 #endif
1736 
1737  if (frame_finished) {
1738  packet_status.audio_decoded++;
1739 
1740  // This can be different than the current packet, so we need to look
1741  // at the current AVFrame from the audio decoder. This timestamp should
1742  // be used for the remainder of this function
1743  audio_pts = audio_frame->pts;
1744 
1745  // Determine related video frame and starting sample # from audio PTS
1746  location = GetAudioPTSLocation(audio_pts);
1747 
1748  // determine how many samples were decoded
1749  int plane_size = -1;
1750 #if HAVE_CH_LAYOUT
1751  int nb_channels = AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->ch_layout.nb_channels;
1752 #else
1753  int nb_channels = AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->channels;
1754 #endif
1755  data_size = av_samples_get_buffer_size(&plane_size, nb_channels,
1756  audio_frame->nb_samples, (AVSampleFormat) (AV_GET_SAMPLE_FORMAT(aStream, aCodecCtx)), 1);
1757 
1758  // Calculate total number of samples
1759  packet_samples = audio_frame->nb_samples * nb_channels;
1760  } else {
1761  if (audio_frame) {
1762  // Free audio frame
1763  AV_FREE_FRAME(&audio_frame);
1764  }
1765  }
1766 
1767  // Estimate the # of samples and the end of this packet's location (to prevent GAPS for the next timestamp)
1768  int pts_remaining_samples = packet_samples / info.channels; // Adjust for zero based array
1769 
1770  // Bail if no samples found
1771  if (pts_remaining_samples == 0) {
1772  ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ProcessAudioPacket (No samples, bailing)",
1773  "packet_samples", packet_samples,
1774  "info.channels", info.channels,
1775  "pts_remaining_samples", pts_remaining_samples);
1776  return;
1777  }
1778 
1779  while (pts_remaining_samples) {
1780  // Get Samples per frame (for this frame number)
1781  int samples_per_frame = Frame::GetSamplesPerFrame(previous_packet_location.frame, info.fps, info.sample_rate, info.channels);
1782 
1783  // Calculate # of samples to add to this frame
1784  int samples = samples_per_frame - previous_packet_location.sample_start;
1785  if (samples > pts_remaining_samples)
1786  samples = pts_remaining_samples;
1787 
1788  // Decrement remaining samples
1789  pts_remaining_samples -= samples;
1790 
1791  if (pts_remaining_samples > 0) {
1792  // next frame
1793  previous_packet_location.frame++;
1794  previous_packet_location.sample_start = 0;
1795  } else {
1796  // Increment sample start
1797  previous_packet_location.sample_start += samples;
1798  }
1799  }
1800 
1801  ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ProcessAudioPacket (ReSample)",
1802  "packet_samples", packet_samples,
1803  "info.channels", info.channels,
1804  "info.sample_rate", info.sample_rate,
1805  "aCodecCtx->sample_fmt", AV_GET_SAMPLE_FORMAT(aStream, aCodecCtx));
1806 
1807  // Create output frame
1808  AVFrame *audio_converted = AV_ALLOCATE_FRAME();
1809  AV_RESET_FRAME(audio_converted);
1810  audio_converted->nb_samples = audio_frame->nb_samples;
1811  av_samples_alloc(audio_converted->data, audio_converted->linesize, info.channels, audio_frame->nb_samples, AV_SAMPLE_FMT_FLTP, 0);
1812 
1813  SWRCONTEXT *avr = avr_ctx;
1814  // setup resample context if needed
1815  if (!avr) {
1816  avr = SWR_ALLOC();
1817 #if HAVE_CH_LAYOUT
1818  av_opt_set_chlayout(avr, "in_chlayout", &AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->ch_layout, 0);
1819  av_opt_set_chlayout(avr, "out_chlayout", &AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->ch_layout, 0);
1820 #else
1821  av_opt_set_int(avr, "in_channel_layout", AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->channel_layout, 0);
1822  av_opt_set_int(avr, "out_channel_layout", AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->channel_layout, 0);
1823  av_opt_set_int(avr, "in_channels", info.channels, 0);
1824  av_opt_set_int(avr, "out_channels", info.channels, 0);
1825 #endif
1826  av_opt_set_int(avr, "in_sample_fmt", AV_GET_SAMPLE_FORMAT(aStream, aCodecCtx), 0);
1827  av_opt_set_int(avr, "out_sample_fmt", AV_SAMPLE_FMT_FLTP, 0);
1828  av_opt_set_int(avr, "in_sample_rate", info.sample_rate, 0);
1829  av_opt_set_int(avr, "out_sample_rate", info.sample_rate, 0);
1830  SWR_INIT(avr);
1831  avr_ctx = avr;
1832  }
1833 
1834  // Convert audio samples
1835  int nb_samples = SWR_CONVERT(avr, // audio resample context
1836  audio_converted->data, // output data pointers
1837  audio_converted->linesize[0], // output plane size, in bytes. (0 if unknown)
1838  audio_converted->nb_samples, // maximum number of samples that the output buffer can hold
1839  audio_frame->data, // input data pointers
1840  audio_frame->linesize[0], // input plane size, in bytes (0 if unknown)
1841  audio_frame->nb_samples); // number of input samples to convert
1842 
1843 
1844  int64_t starting_frame_number = -1;
1845  for (int channel_filter = 0; channel_filter < info.channels; channel_filter++) {
1846  // Array of floats (to hold samples for each channel)
1847  starting_frame_number = location.frame;
1848  int channel_buffer_size = nb_samples;
1849  auto *channel_buffer = (float *) (audio_converted->data[channel_filter]);
1850 
1851  // Loop through samples, and add them to the correct frames
1852  int start = location.sample_start;
1853  int remaining_samples = channel_buffer_size;
1854  while (remaining_samples > 0) {
1855  // Get Samples per frame (for this frame number)
1856  int samples_per_frame = Frame::GetSamplesPerFrame(starting_frame_number, info.fps, info.sample_rate, info.channels);
1857 
1858  // Calculate # of samples to add to this frame
1859  int samples = std::fmin(samples_per_frame - start, remaining_samples);
1860 
1861  // Create or get the existing frame object
1862  std::shared_ptr<Frame> f = CreateFrame(starting_frame_number);
1863 
1864  // Add samples for current channel to the frame.
1865  f->AddAudio(true, channel_filter, start, channel_buffer, samples, 1.0f);
1866 
1867  // Debug output
1868  ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ProcessAudioPacket (f->AddAudio)",
1869  "frame", starting_frame_number,
1870  "start", start,
1871  "samples", samples,
1872  "channel", channel_filter,
1873  "samples_per_frame", samples_per_frame);
1874 
1875  // Add or update cache
1876  working_cache.Add(f);
1877 
1878  // Decrement remaining samples
1879  remaining_samples -= samples;
1880 
1881  // Increment buffer (to next set of samples)
1882  if (remaining_samples > 0)
1883  channel_buffer += samples;
1884 
1885  // Increment frame number
1886  starting_frame_number++;
1887 
1888  // Reset starting sample #
1889  start = 0;
1890  }
1891  }
1892 
1893  // Free AVFrames
1894  av_free(audio_converted->data[0]);
1895  AV_FREE_FRAME(&audio_converted);
1896  AV_FREE_FRAME(&audio_frame);
1897 
1898  // Get audio PTS in seconds
1899  audio_pts_seconds = (double(audio_pts) * info.audio_timebase.ToDouble()) + pts_offset_seconds;
1900 
1901  // Debug output
1902  ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ProcessAudioPacket (After)",
1903  "requested_frame", requested_frame,
1904  "starting_frame", location.frame,
1905  "end_frame", starting_frame_number - 1,
1906  "audio_pts_seconds", audio_pts_seconds);
1907 
1908 }
1909 
1910 
1911 // Seek to a specific frame. This is not always frame accurate, it's more of an estimation on many codecs.
1912 void FFmpegReader::Seek(int64_t requested_frame) {
1913  // Adjust for a requested frame that is too small or too large
1914  if (requested_frame < 1)
1915  requested_frame = 1;
1916  if (requested_frame > info.video_length)
1917  requested_frame = info.video_length;
1918  if (requested_frame > largest_frame_processed && packet_status.end_of_file) {
1919  // Not possible to search past largest_frame once EOF is reached (no more packets)
1920  return;
1921  }
1922 
1923  // Debug output
1924  ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::Seek",
1925  "requested_frame", requested_frame,
1926  "seek_count", seek_count,
1927  "last_frame", last_frame);
1928 
1929  // Clear working cache (since we are seeking to another location in the file)
1930  working_cache.Clear();
1931 
1932  // Reset the last frame variable
1933  video_pts = 0.0;
1934  video_pts_seconds = NO_PTS_OFFSET;
1935  audio_pts = 0.0;
1936  audio_pts_seconds = NO_PTS_OFFSET;
1937  hold_packet = false;
1938  last_frame = 0;
1939  current_video_frame = 0;
1940  largest_frame_processed = 0;
1941  bool has_audio_override = info.has_audio;
1942  bool has_video_override = info.has_video;
1943 
1944  // Init end-of-file detection variables
1945  packet_status.reset(false);
1946 
1947  // Increment seek count
1948  seek_count++;
1949 
1950  // If seeking near frame 1, we need to close and re-open the file (this is more reliable than seeking)
1951  int buffer_amount = 12;
1952  if (requested_frame - buffer_amount < 20) {
1953  // prevent Open() from seeking again
1954  is_seeking = true;
1955 
1956  // Close and re-open file (basically seeking to frame 1)
1957  Close();
1958  Open();
1959 
1960  // Update overrides (since closing and re-opening might update these)
1961  info.has_audio = has_audio_override;
1962  info.has_video = has_video_override;
1963 
1964  // Not actually seeking, so clear these flags
1965  is_seeking = false;
1966  if (seek_count == 1) {
1967  // Don't redefine this on multiple seek attempts for a specific frame
1968  seeking_frame = 1;
1969  seeking_pts = ConvertFrameToVideoPTS(1);
1970  }
1971  seek_audio_frame_found = 0; // used to detect which frames to throw away after a seek
1972  seek_video_frame_found = 0; // used to detect which frames to throw away after a seek
1973 
1974  } else {
1975  // Seek to nearest key-frame (aka, i-frame)
1976  bool seek_worked = false;
1977  int64_t seek_target = 0;
1978 
1979  // Seek video stream (if any), except album arts
1980  if (!seek_worked && info.has_video && !HasAlbumArt()) {
1981  seek_target = ConvertFrameToVideoPTS(requested_frame - buffer_amount);
1982  if (av_seek_frame(pFormatCtx, info.video_stream_index, seek_target, AVSEEK_FLAG_BACKWARD) < 0) {
1983  fprintf(stderr, "%s: error while seeking video stream\n", pFormatCtx->AV_FILENAME);
1984  } else {
1985  // VIDEO SEEK
1986  is_video_seek = true;
1987  seek_worked = true;
1988  }
1989  }
1990 
1991  // Seek audio stream (if not already seeked... and if an audio stream is found)
1992  if (!seek_worked && info.has_audio) {
1993  seek_target = ConvertFrameToAudioPTS(requested_frame - buffer_amount);
1994  if (av_seek_frame(pFormatCtx, info.audio_stream_index, seek_target, AVSEEK_FLAG_BACKWARD) < 0) {
1995  fprintf(stderr, "%s: error while seeking audio stream\n", pFormatCtx->AV_FILENAME);
1996  } else {
1997  // AUDIO SEEK
1998  is_video_seek = false;
1999  seek_worked = true;
2000  }
2001  }
2002 
2003  // Was the seek successful?
2004  if (seek_worked) {
2005  // Flush audio buffer
2006  if (info.has_audio)
2007  avcodec_flush_buffers(aCodecCtx);
2008 
2009  // Flush video buffer
2010  if (info.has_video)
2011  avcodec_flush_buffers(pCodecCtx);
2012 
2013  // Reset previous audio location to zero
2014  previous_packet_location.frame = -1;
2015  previous_packet_location.sample_start = 0;
2016 
2017  // init seek flags
2018  is_seeking = true;
2019  if (seek_count == 1) {
2020  // Don't redefine this on multiple seek attempts for a specific frame
2021  seeking_pts = seek_target;
2022  seeking_frame = requested_frame;
2023  }
2024  seek_audio_frame_found = 0; // used to detect which frames to throw away after a seek
2025  seek_video_frame_found = 0; // used to detect which frames to throw away after a seek
2026 
2027  } else {
2028  // seek failed
2029  seeking_pts = 0;
2030  seeking_frame = 0;
2031 
2032  // prevent Open() from seeking again
2033  is_seeking = true;
2034 
2035  // Close and re-open file (basically seeking to frame 1)
2036  Close();
2037  Open();
2038 
2039  // Not actually seeking, so clear these flags
2040  is_seeking = false;
2041 
2042  // disable seeking for this reader (since it failed)
2043  enable_seek = false;
2044 
2045  // Update overrides (since closing and re-opening might update these)
2046  info.has_audio = has_audio_override;
2047  info.has_video = has_video_override;
2048  }
2049  }
2050 }
2051 
2052 // Get the PTS for the current video packet
2053 int64_t FFmpegReader::GetPacketPTS() {
2054  if (packet) {
2055  int64_t current_pts = packet->pts;
2056  if (current_pts == AV_NOPTS_VALUE && packet->dts != AV_NOPTS_VALUE)
2057  current_pts = packet->dts;
2058 
2059  // Return adjusted PTS
2060  return current_pts;
2061  } else {
2062  // No packet, return NO PTS
2063  return AV_NOPTS_VALUE;
2064  }
2065 }
2066 
2067 // Update PTS Offset (if any)
2068 void FFmpegReader::UpdatePTSOffset() {
2069  if (pts_offset_seconds != NO_PTS_OFFSET) {
2070  // Skip this method if we have already set PTS offset
2071  return;
2072  }
2073  pts_offset_seconds = 0.0;
2074  double video_pts_offset_seconds = 0.0;
2075  double audio_pts_offset_seconds = 0.0;
2076 
2077  bool has_video_pts = false;
2078  if (!info.has_video) {
2079  // Mark as checked
2080  has_video_pts = true;
2081  }
2082  bool has_audio_pts = false;
2083  if (!info.has_audio) {
2084  // Mark as checked
2085  has_audio_pts = true;
2086  }
2087 
2088  // Loop through the stream (until a packet from all streams is found)
2089  while (!has_video_pts || !has_audio_pts) {
2090  // Get the next packet (if any)
2091  if (GetNextPacket() < 0)
2092  // Break loop when no more packets found
2093  break;
2094 
2095  // Get PTS of this packet
2096  int64_t pts = GetPacketPTS();
2097 
2098  // Video packet
2099  if (!has_video_pts && packet->stream_index == videoStream) {
2100  // Get the video packet start time (in seconds)
2101  video_pts_offset_seconds = 0.0 - (video_pts * info.video_timebase.ToDouble());
2102 
2103  // Is timestamp close to zero (within X seconds)
2104  // Ignore wildly invalid timestamps (i.e. -234923423423)
2105  if (std::abs(video_pts_offset_seconds) <= 10.0) {
2106  has_video_pts = true;
2107  }
2108  }
2109  else if (!has_audio_pts && packet->stream_index == audioStream) {
2110  // Get the audio packet start time (in seconds)
2111  audio_pts_offset_seconds = 0.0 - (pts * info.audio_timebase.ToDouble());
2112 
2113  // Is timestamp close to zero (within X seconds)
2114  // Ignore wildly invalid timestamps (i.e. -234923423423)
2115  if (std::abs(audio_pts_offset_seconds) <= 10.0) {
2116  has_audio_pts = true;
2117  }
2118  }
2119  }
2120 
2121  // Do we have all valid timestamps to determine PTS offset?
2122  if (has_video_pts && has_audio_pts) {
2123  // Set PTS Offset to the smallest offset
2124  // [ video timestamp ]
2125  // [ audio timestamp ]
2126  //
2127  // ** SHIFT TIMESTAMPS TO ZERO **
2128  //
2129  //[ video timestamp ]
2130  // [ audio timestamp ]
2131  //
2132  // Since all offsets are negative at this point, we want the max value, which
2133  // represents the closest to zero
2134  pts_offset_seconds = std::max(video_pts_offset_seconds, audio_pts_offset_seconds);
2135  }
2136 }
2137 
2138 // Convert PTS into Frame Number
2139 int64_t FFmpegReader::ConvertVideoPTStoFrame(int64_t pts) {
2140  // Apply PTS offset
2141  int64_t previous_video_frame = current_video_frame;
2142 
2143  // Get the video packet start time (in seconds)
2144  double video_seconds = (double(pts) * info.video_timebase.ToDouble()) + pts_offset_seconds;
2145 
2146  // Divide by the video timebase, to get the video frame number (frame # is decimal at this point)
2147  int64_t frame = round(video_seconds * info.fps.ToDouble()) + 1;
2148 
2149  // Keep track of the expected video frame #
2150  if (current_video_frame == 0)
2151  current_video_frame = frame;
2152  else {
2153 
2154  // Sometimes frames are duplicated due to identical (or similar) timestamps
2155  if (frame == previous_video_frame) {
2156  // return -1 frame number
2157  frame = -1;
2158  } else {
2159  // Increment expected frame
2160  current_video_frame++;
2161  }
2162  }
2163 
2164  // Return frame #
2165  return frame;
2166 }
2167 
2168 // Convert Frame Number into Video PTS
2169 int64_t FFmpegReader::ConvertFrameToVideoPTS(int64_t frame_number) {
2170  // Get timestamp of this frame (in seconds)
2171  double seconds = (double(frame_number - 1) / info.fps.ToDouble()) + pts_offset_seconds;
2172 
2173  // Calculate the # of video packets in this timestamp
2174  int64_t video_pts = round(seconds / info.video_timebase.ToDouble());
2175 
2176  // Apply PTS offset (opposite)
2177  return video_pts;
2178 }
2179 
2180 // Convert Frame Number into Video PTS
2181 int64_t FFmpegReader::ConvertFrameToAudioPTS(int64_t frame_number) {
2182  // Get timestamp of this frame (in seconds)
2183  double seconds = (double(frame_number - 1) / info.fps.ToDouble()) + pts_offset_seconds;
2184 
2185  // Calculate the # of audio packets in this timestamp
2186  int64_t audio_pts = round(seconds / info.audio_timebase.ToDouble());
2187 
2188  // Apply PTS offset (opposite)
2189  return audio_pts;
2190 }
2191 
2192 // Calculate Starting video frame and sample # for an audio PTS
2193 AudioLocation FFmpegReader::GetAudioPTSLocation(int64_t pts) {
2194  // Get the audio packet start time (in seconds)
2195  double audio_seconds = (double(pts) * info.audio_timebase.ToDouble()) + pts_offset_seconds;
2196 
2197  // Divide by the video timebase, to get the video frame number (frame # is decimal at this point)
2198  double frame = (audio_seconds * info.fps.ToDouble()) + 1;
2199 
2200  // Frame # as a whole number (no more decimals)
2201  int64_t whole_frame = int64_t(frame);
2202 
2203  // Remove the whole number, and only get the decimal of the frame
2204  double sample_start_percentage = frame - double(whole_frame);
2205 
2206  // Get Samples per frame
2207  int samples_per_frame = Frame::GetSamplesPerFrame(whole_frame, info.fps, info.sample_rate, info.channels);
2208 
2209  // Calculate the sample # to start on
2210  int sample_start = round(double(samples_per_frame) * sample_start_percentage);
2211 
2212  // Protect against broken (i.e. negative) timestamps
2213  if (whole_frame < 1)
2214  whole_frame = 1;
2215  if (sample_start < 0)
2216  sample_start = 0;
2217 
2218  // Prepare final audio packet location
2219  AudioLocation location = {whole_frame, sample_start};
2220 
2221  // Compare to previous audio packet (and fix small gaps due to varying PTS timestamps)
2222  if (previous_packet_location.frame != -1) {
2223  if (location.is_near(previous_packet_location, samples_per_frame, samples_per_frame)) {
2224  int64_t orig_frame = location.frame;
2225  int orig_start = location.sample_start;
2226 
2227  // Update sample start, to prevent gaps in audio
2228  location.sample_start = previous_packet_location.sample_start;
2229  location.frame = previous_packet_location.frame;
2230 
2231  // Debug output
2232  ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::GetAudioPTSLocation (Audio Gap Detected)", "Source Frame", orig_frame, "Source Audio Sample", orig_start, "Target Frame", location.frame, "Target Audio Sample", location.sample_start, "pts", pts);
2233 
2234  } else {
2235  // Debug output
2236  ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::GetAudioPTSLocation (Audio Gap Ignored - too big)", "Previous location frame", previous_packet_location.frame, "Target Frame", location.frame, "Target Audio Sample", location.sample_start, "pts", pts);
2237  }
2238  }
2239 
2240  // Set previous location
2241  previous_packet_location = location;
2242 
2243  // Return the associated video frame and starting sample #
2244  return location;
2245 }
2246 
2247 // Create a new Frame (or return an existing one) and add it to the working queue.
2248 std::shared_ptr<Frame> FFmpegReader::CreateFrame(int64_t requested_frame) {
2249  // Check working cache
2250  std::shared_ptr<Frame> output = working_cache.GetFrame(requested_frame);
2251 
2252  if (!output) {
2253  // (re-)Check working cache
2254  output = working_cache.GetFrame(requested_frame);
2255  if(output) return output;
2256 
2257  // Create a new frame on the working cache
2258  output = std::make_shared<Frame>(requested_frame, info.width, info.height, "#000000", Frame::GetSamplesPerFrame(requested_frame, info.fps, info.sample_rate, info.channels), info.channels);
2259  output->SetPixelRatio(info.pixel_ratio.num, info.pixel_ratio.den); // update pixel ratio
2260  output->ChannelsLayout(info.channel_layout); // update audio channel layout from the parent reader
2261  output->SampleRate(info.sample_rate); // update the frame's sample rate of the parent reader
2262 
2263  working_cache.Add(output);
2264 
2265  // Set the largest processed frame (if this is larger)
2266  if (requested_frame > largest_frame_processed)
2267  largest_frame_processed = requested_frame;
2268  }
2269  // Return frame
2270  return output;
2271 }
2272 
2273 // Determine if frame is partial due to seek
2274 bool FFmpegReader::IsPartialFrame(int64_t requested_frame) {
2275 
2276  // Sometimes a seek gets partial frames, and we need to remove them
2277  bool seek_trash = false;
2278  int64_t max_seeked_frame = seek_audio_frame_found; // determine max seeked frame
2279  if (seek_video_frame_found > max_seeked_frame) {
2280  max_seeked_frame = seek_video_frame_found;
2281  }
2282  if ((info.has_audio && seek_audio_frame_found && max_seeked_frame >= requested_frame) ||
2283  (info.has_video && seek_video_frame_found && max_seeked_frame >= requested_frame)) {
2284  seek_trash = true;
2285  }
2286 
2287  return seek_trash;
2288 }
2289 
2290 // Check the working queue, and move finished frames to the finished queue
2291 void FFmpegReader::CheckWorkingFrames(int64_t requested_frame) {
2292 
2293  // Prevent async calls to the following code
2294  const std::lock_guard<std::recursive_mutex> lock(getFrameMutex);
2295 
2296  // Get a list of current working queue frames in the cache (in-progress frames)
2297  std::vector<std::shared_ptr<openshot::Frame>> working_frames = working_cache.GetFrames();
2298  std::vector<std::shared_ptr<openshot::Frame>>::iterator working_itr;
2299 
2300  // Loop through all working queue frames (sorted by frame #)
2301  for(working_itr = working_frames.begin(); working_itr != working_frames.end(); ++working_itr)
2302  {
2303  // Get working frame
2304  std::shared_ptr<Frame> f = *working_itr;
2305 
2306  // Was a frame found? Is frame requested yet?
2307  if (!f || f->number > requested_frame) {
2308  // If not, skip to next one
2309  continue;
2310  }
2311 
2312  // Calculate PTS in seconds (of working frame), and the most recent processed pts value
2313  double frame_pts_seconds = (double(f->number - 1) / info.fps.ToDouble()) + pts_offset_seconds;
2314  double recent_pts_seconds = std::max(video_pts_seconds, audio_pts_seconds);
2315 
2316  // Determine if video and audio are ready (based on timestamps)
2317  bool is_video_ready = false;
2318  bool is_audio_ready = false;
2319  double recent_pts_diff = recent_pts_seconds - frame_pts_seconds;
2320  if ((frame_pts_seconds <= video_pts_seconds)
2321  || (recent_pts_diff > 1.5)
2322  || packet_status.video_eof || packet_status.end_of_file) {
2323  // Video stream is past this frame (so it must be done)
2324  // OR video stream is too far behind, missing, or end-of-file
2325  is_video_ready = true;
2326  ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::CheckWorkingFrames (video ready)",
2327  "frame_number", f->number,
2328  "frame_pts_seconds", frame_pts_seconds,
2329  "video_pts_seconds", video_pts_seconds,
2330  "recent_pts_diff", recent_pts_diff);
2331  if (info.has_video && !f->has_image_data) {
2332  // Frame has no image data (copy from previous frame)
2333  // Loop backwards through final frames (looking for the nearest, previous frame image)
2334  for (int64_t previous_frame = requested_frame - 1; previous_frame > 0; previous_frame--) {
2335  std::shared_ptr<Frame> previous_frame_instance = final_cache.GetFrame(previous_frame);
2336  if (previous_frame_instance && previous_frame_instance->has_image_data) {
2337  // Copy image from last decoded frame
2338  f->AddImage(std::make_shared<QImage>(previous_frame_instance->GetImage()->copy()));
2339  break;
2340  }
2341  }
2342 
2343  if (last_video_frame && !f->has_image_data) {
2344  // Copy image from last decoded frame
2345  f->AddImage(std::make_shared<QImage>(last_video_frame->GetImage()->copy()));
2346  } else if (!f->has_image_data) {
2347  f->AddColor("#000000");
2348  }
2349  }
2350  }
2351 
2352  double audio_pts_diff = audio_pts_seconds - frame_pts_seconds;
2353  if ((frame_pts_seconds < audio_pts_seconds && audio_pts_diff > 1.0)
2354  || (recent_pts_diff > 1.5)
2355  || packet_status.audio_eof || packet_status.end_of_file) {
2356  // Audio stream is past this frame (so it must be done)
2357  // OR audio stream is too far behind, missing, or end-of-file
2358  // Adding a bit of margin here, to allow for partial audio packets
2359  is_audio_ready = true;
2360  ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::CheckWorkingFrames (audio ready)",
2361  "frame_number", f->number,
2362  "frame_pts_seconds", frame_pts_seconds,
2363  "audio_pts_seconds", audio_pts_seconds,
2364  "audio_pts_diff", audio_pts_diff,
2365  "recent_pts_diff", recent_pts_diff);
2366  }
2367  bool is_seek_trash = IsPartialFrame(f->number);
2368 
2369  // Adjust for available streams
2370  if (!info.has_video) is_video_ready = true;
2371  if (!info.has_audio) is_audio_ready = true;
2372 
2373  // Debug output
2374  ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::CheckWorkingFrames",
2375  "frame_number", f->number,
2376  "is_video_ready", is_video_ready,
2377  "is_audio_ready", is_audio_ready,
2378  "video_eof", packet_status.video_eof,
2379  "audio_eof", packet_status.audio_eof,
2380  "end_of_file", packet_status.end_of_file);
2381 
2382  // Check if working frame is final
2383  if ((!packet_status.end_of_file && is_video_ready && is_audio_ready) || packet_status.end_of_file || is_seek_trash) {
2384  // Debug output
2385  ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::CheckWorkingFrames (mark frame as final)",
2386  "requested_frame", requested_frame,
2387  "f->number", f->number,
2388  "is_seek_trash", is_seek_trash,
2389  "Working Cache Count", working_cache.Count(),
2390  "Final Cache Count", final_cache.Count(),
2391  "end_of_file", packet_status.end_of_file);
2392 
2393  if (!is_seek_trash) {
2394  // Move frame to final cache
2395  final_cache.Add(f);
2396 
2397  // Remove frame from working cache
2398  working_cache.Remove(f->number);
2399 
2400  // Update last frame processed
2401  last_frame = f->number;
2402  } else {
2403  // Seek trash, so delete the frame from the working cache, and never add it to the final cache.
2404  working_cache.Remove(f->number);
2405  }
2406 
2407  }
2408  }
2409 
2410  // Clear vector of frames
2411  working_frames.clear();
2412  working_frames.shrink_to_fit();
2413 }
2414 
2415 // Check for the correct frames per second (FPS) value by scanning the 1st few seconds of video packets.
2416 void FFmpegReader::CheckFPS() {
2417  if (check_fps) {
2418  // Do not check FPS more than 1 time
2419  return;
2420  } else {
2421  check_fps = true;
2422  }
2423 
2424  int frames_per_second[3] = {0,0,0};
2425  int max_fps_index = sizeof(frames_per_second) / sizeof(frames_per_second[0]);
2426  int fps_index = 0;
2427 
2428  int all_frames_detected = 0;
2429  int starting_frames_detected = 0;
2430 
2431  // Loop through the stream
2432  while (true) {
2433  // Get the next packet (if any)
2434  if (GetNextPacket() < 0)
2435  // Break loop when no more packets found
2436  break;
2437 
2438  // Video packet
2439  if (packet->stream_index == videoStream) {
2440  // Get the video packet start time (in seconds)
2441  double video_seconds = (double(GetPacketPTS()) * info.video_timebase.ToDouble()) + pts_offset_seconds;
2442  fps_index = int(video_seconds); // truncate float timestamp to int (second 1, second 2, second 3)
2443 
2444  // Is this video packet from the first few seconds?
2445  if (fps_index >= 0 && fps_index < max_fps_index) {
2446  // Yes, keep track of how many frames per second (over the first few seconds)
2447  starting_frames_detected++;
2448  frames_per_second[fps_index]++;
2449  }
2450 
2451  // Track all video packets detected
2452  all_frames_detected++;
2453  }
2454  }
2455 
2456  // Calculate FPS (based on the first few seconds of video packets)
2457  float avg_fps = 30.0;
2458  if (starting_frames_detected > 0 && fps_index > 0) {
2459  avg_fps = float(starting_frames_detected) / std::min(fps_index, max_fps_index);
2460  }
2461 
2462  // Verify average FPS is a reasonable value
2463  if (avg_fps < 8.0) {
2464  // Invalid FPS assumed, so switching to a sane default FPS instead
2465  avg_fps = 30.0;
2466  }
2467 
2468  // Update FPS (truncate average FPS to Integer)
2469  info.fps = Fraction(int(avg_fps), 1);
2470 
2471  // Update Duration and Length
2472  if (all_frames_detected > 0) {
2473  // Use all video frames detected to calculate # of frames
2474  info.video_length = all_frames_detected;
2475  info.duration = all_frames_detected / avg_fps;
2476  } else {
2477  // Use previous duration to calculate # of frames
2478  info.video_length = info.duration * avg_fps;
2479  }
2480 
2481  // Update video bit rate
2483 }
2484 
2485 // Remove AVFrame from cache (and deallocate its memory)
2486 void FFmpegReader::RemoveAVFrame(AVFrame *remove_frame) {
2487  // Remove pFrame (if exists)
2488  if (remove_frame) {
2489  // Free memory
2490  av_freep(&remove_frame->data[0]);
2491 #ifndef WIN32
2492  AV_FREE_FRAME(&remove_frame);
2493 #endif
2494  }
2495 }
2496 
2497 // Remove AVPacket from cache (and deallocate its memory)
2498 void FFmpegReader::RemoveAVPacket(AVPacket *remove_packet) {
2499  // deallocate memory for packet
2500  AV_FREE_PACKET(remove_packet);
2501 
2502  // Delete the object
2503  delete remove_packet;
2504 }
2505 
2506 // Generate JSON string of this object
2507 std::string FFmpegReader::Json() const {
2508 
2509  // Return formatted string
2510  return JsonValue().toStyledString();
2511 }
2512 
2513 // Generate Json::Value for this object
2514 Json::Value FFmpegReader::JsonValue() const {
2515 
2516  // Create root json object
2517  Json::Value root = ReaderBase::JsonValue(); // get parent properties
2518  root["type"] = "FFmpegReader";
2519  root["path"] = path;
2520  switch (duration_strategy) {
2522  root["duration_strategy"] = "VideoPreferred";
2523  break;
2525  root["duration_strategy"] = "AudioPreferred";
2526  break;
2528  default:
2529  root["duration_strategy"] = "LongestStream";
2530  break;
2531  }
2532 
2533  // return JsonValue
2534  return root;
2535 }
2536 
2537 // Load JSON string into this object
2538 void FFmpegReader::SetJson(const std::string value) {
2539 
2540  // Parse JSON string into JSON objects
2541  try {
2542  const Json::Value root = openshot::stringToJson(value);
2543  // Set all values that match
2544  SetJsonValue(root);
2545  }
2546  catch (const std::exception& e) {
2547  // Error parsing JSON (or missing keys)
2548  throw InvalidJSON("JSON is invalid (missing keys or invalid data types)");
2549  }
2550 }
2551 
2552 // Load Json::Value into this object
2553 void FFmpegReader::SetJsonValue(const Json::Value root) {
2554 
2555  // Set parent data
2557 
2558  // Set data from Json (if key is found)
2559  if (!root["path"].isNull())
2560  path = root["path"].asString();
2561  if (!root["duration_strategy"].isNull()) {
2562  const std::string strategy = root["duration_strategy"].asString();
2563  if (strategy == "VideoPreferred") {
2564  duration_strategy = DurationStrategy::VideoPreferred;
2565  } else if (strategy == "AudioPreferred") {
2566  duration_strategy = DurationStrategy::AudioPreferred;
2567  } else {
2568  duration_strategy = DurationStrategy::LongestStream;
2569  }
2570  }
2571 
2572  // Re-Open path, and re-init everything (if needed)
2573  if (is_open) {
2574  Close();
2575  Open();
2576  }
2577 }
openshot::stringToJson
const Json::Value stringToJson(const std::string value)
Definition: Json.cpp:16
openshot::CacheMemory::Clear
void Clear()
Clear the cache of all frames.
Definition: CacheMemory.cpp:238
AV_FIND_DECODER_CODEC_ID
#define AV_FIND_DECODER_CODEC_ID(av_stream)
Definition: FFmpegUtilities.h:211
openshot::ReaderInfo::sample_rate
int sample_rate
The number of audio samples per second (44100 is a common sample rate)
Definition: ReaderBase.h:60
openshot::FFmpegReader::FFmpegReader
FFmpegReader(const std::string &path, bool inspect_reader=true)
Constructor for FFmpegReader.
Definition: FFmpegReader.cpp:76
openshot::Fraction::ToFloat
float ToFloat()
Return this fraction as a float (i.e. 1/2 = 0.5)
Definition: Fraction.cpp:35
openshot::Settings::HARDWARE_DECODER
int HARDWARE_DECODER
Use video codec for faster video decoding (if supported)
Definition: Settings.h:62
openshot::Coordinate::Y
double Y
The Y value of the coordinate (usually representing the value of the property being animated)
Definition: Coordinate.h:41
openshot::CacheMemory::Count
int64_t Count()
Count the frames in the queue.
Definition: CacheMemory.cpp:256
FFmpegUtilities.h
Header file for FFmpegUtilities.
openshot::ReaderBase::JsonValue
virtual Json::Value JsonValue() const =0
Generate Json::Value for this object.
Definition: ReaderBase.cpp:106
openshot::InvalidCodec
Exception when no valid codec is found for a file.
Definition: Exceptions.h:172
openshot::TimelineBase::preview_width
int preview_width
Optional preview width of timeline image. If your preview window is smaller than the timeline,...
Definition: TimelineBase.h:44
openshot::PacketStatus::reset
void reset(bool eof)
Definition: FFmpegReader.h:70
openshot::CacheMemory::GetFrame
std::shared_ptr< openshot::Frame > GetFrame(int64_t frame_number)
Get a frame from the cache.
Definition: CacheMemory.cpp:81
openshot::FFmpegReader::GetFrame
std::shared_ptr< openshot::Frame > GetFrame(int64_t requested_frame) override
Definition: FFmpegReader.cpp:1037
AV_COPY_PICTURE_DATA
#define AV_COPY_PICTURE_DATA(av_frame, buffer, pix_fmt, width, height)
Definition: FFmpegUtilities.h:223
openshot::CacheMemory::Add
void Add(std::shared_ptr< openshot::Frame > frame)
Add a Frame to the cache.
Definition: CacheMemory.cpp:47
PixelFormat
#define PixelFormat
Definition: FFmpegUtilities.h:107
AV_ALLOCATE_FRAME
#define AV_ALLOCATE_FRAME()
Definition: FFmpegUtilities.h:203
openshot::ReaderBase::SetJsonValue
virtual void SetJsonValue(const Json::Value root)=0
Load Json::Value into this object.
Definition: ReaderBase.cpp:157
SWR_CONVERT
#define SWR_CONVERT(ctx, out, linesize, out_count, in, linesize2, in_count)
Definition: FFmpegUtilities.h:149
openshot
This namespace is the default namespace for all code in the openshot library.
Definition: Compressor.h:28
openshot::Point::co
Coordinate co
This is the primary coordinate.
Definition: Point.h:66
openshot::Clip::scale_y
openshot::Keyframe scale_y
Curve representing the vertical scaling in percent (0 to 1)
Definition: Clip.h:317
openshot::AudioLocation
This struct holds the associated video frame and starting sample # for an audio packet.
Definition: AudioLocation.h:25
openshot::AudioLocation::frame
int64_t frame
Definition: AudioLocation.h:26
openshot::Clip
This class represents a clip (used to arrange readers on the timeline)
Definition: Clip.h:89
openshot::DurationStrategy::AudioPreferred
@ AudioPreferred
Prefer the audio stream's duration, fallback to video then container.
openshot::Fraction
This class represents a fraction.
Definition: Fraction.h:30
openshot::AudioLocation::sample_start
int sample_start
Definition: AudioLocation.h:27
AV_FREE_FRAME
#define AV_FREE_FRAME(av_frame)
Definition: FFmpegUtilities.h:207
MemoryTrim.h
Cross-platform helper to encourage returning freed memory to the OS.
openshot::Keyframe::GetMaxPoint
Point GetMaxPoint() const
Get max point (by Y coordinate)
Definition: KeyFrame.cpp:245
openshot::ReaderBase::info
openshot::ReaderInfo info
Information about the current media file.
Definition: ReaderBase.h:88
openshot::ReaderInfo::interlaced_frame
bool interlaced_frame
Definition: ReaderBase.h:56
Timeline.h
Header file for Timeline class.
openshot::Clip::ParentTimeline
void ParentTimeline(openshot::TimelineBase *new_timeline) override
Set associated Timeline pointer.
Definition: Clip.cpp:446
openshot::FFmpegReader::~FFmpegReader
virtual ~FFmpegReader()
Destructor.
Definition: FFmpegReader.cpp:108
openshot::ReaderInfo::audio_bit_rate
int audio_bit_rate
The bit rate of the audio stream (in bytes)
Definition: ReaderBase.h:59
openshot::CacheMemory::Remove
void Remove(int64_t frame_number)
Remove a specific frame.
Definition: CacheMemory.cpp:155
AV_FREE_PACKET
#define AV_FREE_PACKET(av_packet)
Definition: FFmpegUtilities.h:208
openshot::ReaderInfo::duration
float duration
Length of time (in seconds)
Definition: ReaderBase.h:43
openshot::ReaderInfo::has_video
bool has_video
Determines if this file has a video stream.
Definition: ReaderBase.h:40
openshot::FFmpegReader::JsonValue
Json::Value JsonValue() const override
Generate Json::Value for this object.
Definition: FFmpegReader.cpp:2514
openshot::PacketStatus::audio_read
int64_t audio_read
Definition: FFmpegReader.h:51
openshot::ReaderInfo::width
int width
The width of the video (in pixesl)
Definition: ReaderBase.h:46
openshot::LAYOUT_STEREO
@ LAYOUT_STEREO
Definition: ChannelLayouts.h:31
openshot::FFmpegReader::SetJson
void SetJson(const std::string value) override
Load JSON string into this object.
Definition: FFmpegReader.cpp:2538
openshot::PacketStatus::packets_eof
bool packets_eof
Definition: FFmpegReader.h:57
hw_de_av_pix_fmt_global
AVPixelFormat hw_de_av_pix_fmt_global
Definition: FFmpegReader.cpp:72
openshot::PacketStatus::audio_decoded
int64_t audio_decoded
Definition: FFmpegReader.h:52
openshot::Fraction::ToDouble
double ToDouble() const
Return this fraction as a double (i.e. 1/2 = 0.5)
Definition: Fraction.cpp:40
openshot::PacketStatus::video_read
int64_t video_read
Definition: FFmpegReader.h:49
hw_de_on
int hw_de_on
Definition: FFmpegReader.cpp:70
openshot::CacheBase::SetMaxBytesFromInfo
void SetMaxBytesFromInfo(int64_t number_of_frames, int width, int height, int sample_rate, int channels)
Set maximum bytes to a different amount based on a ReaderInfo struct.
Definition: CacheBase.cpp:28
AV_ALLOCATE_IMAGE
#define AV_ALLOCATE_IMAGE(av_frame, pix_fmt, width, height)
Definition: FFmpegUtilities.h:204
openshot::LAYOUT_MONO
@ LAYOUT_MONO
Definition: ChannelLayouts.h:30
openshot::Clip::scale_x
openshot::Keyframe scale_x
Curve representing the horizontal scaling in percent (0 to 1)
Definition: Clip.h:316
AV_GET_CODEC_ATTRIBUTES
#define AV_GET_CODEC_ATTRIBUTES(av_stream, av_context)
Definition: FFmpegUtilities.h:218
openshot::ReaderInfo::video_length
int64_t video_length
The number of frames in the video stream.
Definition: ReaderBase.h:53
hw_de_av_device_type_global
AVHWDeviceType hw_de_av_device_type_global
Definition: FFmpegReader.cpp:73
openshot::ReaderInfo::height
int height
The height of the video (in pixels)
Definition: ReaderBase.h:45
openshot::PacketStatus::video_eof
bool video_eof
Definition: FFmpegReader.h:55
openshot::Fraction::num
int num
Numerator for the fraction.
Definition: Fraction.h:32
if
if(!codec) codec
ZmqLogger.h
Header file for ZeroMQ-based Logger class.
openshot::Fraction::den
int den
Denominator for the fraction.
Definition: Fraction.h:33
AV_RESET_FRAME
#define AV_RESET_FRAME(av_frame)
Definition: FFmpegUtilities.h:206
openshot::AudioLocation::is_near
bool is_near(AudioLocation location, int samples_per_frame, int64_t amount)
Definition: FFmpegReader.cpp:115
SWR_CLOSE
#define SWR_CLOSE(ctx)
Definition: FFmpegUtilities.h:152
openshot::ReaderInfo::has_audio
bool has_audio
Determines if this file has an audio stream.
Definition: ReaderBase.h:41
openshot::Settings::DE_LIMIT_HEIGHT_MAX
int DE_LIMIT_HEIGHT_MAX
Maximum rows that hardware decode can handle.
Definition: Settings.h:74
openshot::InvalidJSON
Exception for invalid JSON.
Definition: Exceptions.h:217
openshot::FFmpegReader::enable_seek
bool enable_seek
Definition: FFmpegReader.h:251
openshot::ReaderInfo::file_size
int64_t file_size
Size of file (in bytes)
Definition: ReaderBase.h:44
openshot::Timeline
This class represents a timeline.
Definition: Timeline.h:154
openshot::FFmpegReader::Open
void Open() override
Open File - which is called by the constructor automatically.
Definition: FFmpegReader.cpp:215
openshot::OutOfMemory
Exception when memory could not be allocated.
Definition: Exceptions.h:348
openshot::SCALE_CROP
@ SCALE_CROP
Scale the clip until both height and width fill the canvas (cropping the overlap)
Definition: Enums.h:37
SWR_INIT
#define SWR_INIT(ctx)
Definition: FFmpegUtilities.h:154
SWRCONTEXT
#define SWRCONTEXT
Definition: FFmpegUtilities.h:155
openshot::PacketStatus::audio_eof
bool audio_eof
Definition: FFmpegReader.h:56
openshot::ReaderInfo::has_single_image
bool has_single_image
Determines if this file only contains a single image.
Definition: ReaderBase.h:42
openshot::FFmpegReader::final_cache
CacheMemory final_cache
Final cache object used to hold final frames.
Definition: FFmpegReader.h:247
openshot::ReaderInfo::video_timebase
openshot::Fraction video_timebase
The video timebase determines how long each frame stays on the screen.
Definition: ReaderBase.h:55
openshot::Settings::Instance
static Settings * Instance()
Create or get an instance of this logger singleton (invoke the class with this method)
Definition: Settings.cpp:23
CropHelpers.h
Shared helpers for Crop effect scaling logic.
openshot::ReaderInfo::metadata
std::map< std::string, std::string > metadata
An optional map/dictionary of metadata for this reader.
Definition: ReaderBase.h:65
openshot::DurationStrategy::LongestStream
@ LongestStream
Use the longest value from video, audio, or container.
openshot::FFmpegReader
This class uses the FFmpeg libraries, to open video files and audio files, and return openshot::Frame...
Definition: FFmpegReader.h:103
path
path
Definition: FFmpegWriter.cpp:1469
openshot::Frame::GetSamplesPerFrame
int GetSamplesPerFrame(openshot::Fraction fps, int sample_rate, int channels)
Calculate the # of samples per video frame (for the current frame number)
Definition: Frame.cpp:484
openshot::InvalidFile
Exception for files that can not be found or opened.
Definition: Exceptions.h:187
openshot::ReaderInfo::audio_stream_index
int audio_stream_index
The index of the audio stream.
Definition: ReaderBase.h:63
openshot::ZmqLogger::Instance
static ZmqLogger * Instance()
Create or get an instance of this logger singleton (invoke the class with this method)
Definition: ZmqLogger.cpp:35
openshot::DurationStrategy
DurationStrategy
This enumeration determines which duration source to favor.
Definition: Enums.h:60
openshot::ReaderInfo::audio_timebase
openshot::Fraction audio_timebase
The audio timebase determines how long each audio packet should be played.
Definition: ReaderBase.h:64
openshot::FFmpegReader::Close
void Close() override
Close File.
Definition: FFmpegReader.cpp:640
openshot::SCALE_FIT
@ SCALE_FIT
Scale the clip until either height or width fills the canvas (with no cropping)
Definition: Enums.h:38
openshot::PacketStatus::packets_read
int64_t packets_read()
Definition: FFmpegReader.h:60
openshot::ReaderInfo::pixel_format
int pixel_format
The pixel format (i.e. YUV420P, RGB24, etc...)
Definition: ReaderBase.h:47
openshot::ZmqLogger::AppendDebugMethod
void AppendDebugMethod(std::string method_name, std::string arg1_name="", float arg1_value=-1.0, std::string arg2_name="", float arg2_value=-1.0, std::string arg3_name="", float arg3_value=-1.0, std::string arg4_name="", float arg4_value=-1.0, std::string arg5_name="", float arg5_value=-1.0, std::string arg6_name="", float arg6_value=-1.0)
Append debug information.
Definition: ZmqLogger.cpp:178
openshot::ReaderInfo::vcodec
std::string vcodec
The name of the video codec used to encode / decode the video stream.
Definition: ReaderBase.h:52
openshot::PacketStatus::packets_decoded
int64_t packets_decoded()
Definition: FFmpegReader.h:65
AV_GET_CODEC_TYPE
#define AV_GET_CODEC_TYPE(av_stream)
Definition: FFmpegUtilities.h:210
openshot::ReaderClosed
Exception when a reader is closed, and a frame is requested.
Definition: Exceptions.h:363
openshot::ReaderInfo::channel_layout
openshot::ChannelLayout channel_layout
The channel layout (mono, stereo, 5 point surround, etc...)
Definition: ReaderBase.h:62
AV_FREE_CONTEXT
#define AV_FREE_CONTEXT(av_context)
Definition: FFmpegUtilities.h:209
PIX_FMT_RGBA
#define PIX_FMT_RGBA
Definition: FFmpegUtilities.h:110
AV_GET_CODEC_PIXEL_FORMAT
#define AV_GET_CODEC_PIXEL_FORMAT(av_stream, av_context)
Definition: FFmpegUtilities.h:219
AVCODEC_REGISTER_ALL
#define AVCODEC_REGISTER_ALL
Definition: FFmpegUtilities.h:199
SWR_FREE
#define SWR_FREE(ctx)
Definition: FFmpegUtilities.h:153
openshot::Settings::DE_LIMIT_WIDTH_MAX
int DE_LIMIT_WIDTH_MAX
Maximum columns that hardware decode can handle.
Definition: Settings.h:77
openshot::ReaderInfo::fps
openshot::Fraction fps
Frames per second, as a fraction (i.e. 24/1 = 24 fps)
Definition: ReaderBase.h:48
AV_GET_SAMPLE_FORMAT
#define AV_GET_SAMPLE_FORMAT(av_stream, av_context)
Definition: FFmpegUtilities.h:221
FF_AUDIO_NUM_PROCESSORS
#define FF_AUDIO_NUM_PROCESSORS
Definition: OpenMPUtilities.h:25
openshot::ReaderInfo::video_bit_rate
int video_bit_rate
The bit rate of the video stream (in bytes)
Definition: ReaderBase.h:49
openshot::PacketStatus::end_of_file
bool end_of_file
Definition: FFmpegReader.h:58
FF_VIDEO_NUM_PROCESSORS
#define FF_VIDEO_NUM_PROCESSORS
Definition: OpenMPUtilities.h:24
openshot::Clip::scale
openshot::ScaleType scale
The scale determines how a clip should be resized to fit its parent.
Definition: Clip.h:177
openshot::ReaderInfo::top_field_first
bool top_field_first
Definition: ReaderBase.h:57
openshot::ChannelLayout
ChannelLayout
This enumeration determines the audio channel layout (such as stereo, mono, 5 point surround,...
Definition: ChannelLayouts.h:28
SWR_ALLOC
#define SWR_ALLOC()
Definition: FFmpegUtilities.h:151
openshot::ReaderInfo::pixel_ratio
openshot::Fraction pixel_ratio
The pixel ratio of the video stream as a fraction (i.e. some pixels are not square)
Definition: ReaderBase.h:50
AV_REGISTER_ALL
#define AV_REGISTER_ALL
Definition: FFmpegUtilities.h:198
openshot::DurationStrategy::VideoPreferred
@ VideoPreferred
Prefer the video stream's duration, fallback to audio then container.
openshot::CacheMemory::GetFrames
std::vector< std::shared_ptr< openshot::Frame > > GetFrames()
Get an array of all Frames.
Definition: CacheMemory.cpp:97
AV_GET_CODEC_CONTEXT
#define AV_GET_CODEC_CONTEXT(av_stream, av_codec)
Definition: FFmpegUtilities.h:212
openshot::ReaderInfo::video_stream_index
int video_stream_index
The index of the video stream.
Definition: ReaderBase.h:54
openshot::FFmpegReader::SetJsonValue
void SetJsonValue(const Json::Value root) override
Load Json::Value into this object.
Definition: FFmpegReader.cpp:2553
openshot::SCALE_STRETCH
@ SCALE_STRETCH
Scale the clip until both height and width fill the canvas (distort to fit)
Definition: Enums.h:39
openshot::ReaderInfo::acodec
std::string acodec
The name of the audio codec used to encode / decode the video stream.
Definition: ReaderBase.h:58
openshot::NoStreamsFound
Exception when no streams are found in the file.
Definition: Exceptions.h:285
openshot::ReaderInfo::display_ratio
openshot::Fraction display_ratio
The ratio of width to height of the video stream (i.e. 640x480 has a ratio of 4/3)
Definition: ReaderBase.h:51
openshot::ReaderInfo::channels
int channels
The number of audio channels used in the audio stream.
Definition: ReaderBase.h:61
openshot::FFmpegReader::Json
std::string Json() const override
Generate JSON string of this object.
Definition: FFmpegReader.cpp:2507
openshot::FFmpegReader::GetIsDurationKnown
bool GetIsDurationKnown()
Return true if frame can be read with GetFrame()
Definition: FFmpegReader.cpp:1033
openshot::ApplyCropResizeScale
void ApplyCropResizeScale(Clip *clip, int source_width, int source_height, int &max_width, int &max_height)
Scale the requested max_width / max_height based on the Crop resize amount, capped by source size.
Definition: CropHelpers.cpp:40
openshot::PacketStatus::video_decoded
int64_t video_decoded
Definition: FFmpegReader.h:50
opts
AVDictionary * opts
Definition: FFmpegWriter.cpp:1476
Exceptions.h
Header file for all Exception classes.
openshot::Settings::HW_DE_DEVICE_SET
int HW_DE_DEVICE_SET
Which GPU to use to decode (0 is the first)
Definition: Settings.h:80
FFmpegReader.h
Header file for FFmpegReader class.
openshot::TrimMemoryToOS
bool TrimMemoryToOS(bool force) noexcept
Attempt to return unused heap memory to the operating system.
Definition: MemoryTrim.cpp:40
openshot::ReaderBase::getFrameMutex
std::recursive_mutex getFrameMutex
Mutex for multiple threads.
Definition: ReaderBase.h:79
openshot::ReaderBase::ParentClip
openshot::ClipBase * ParentClip()
Parent clip object of this reader (which can be unparented and NULL)
Definition: ReaderBase.cpp:240