Vuo  2.3.2
VuoFfmpegDecoder.h
Go to the documentation of this file.
1 
10 #pragma once
11 
12 #include "module.h"
13 
14 #ifdef __cplusplus
15 extern "C"
16 {
17 #endif
18 #include "VuoVideoDecoder.h"
19 #include "VuoVideo.h"
20 #include "VuoImage.h"
21 #include "VuoAudioSamples.h"
22 #include "VuoAudioFrame.h"
24 #include "VuoVideoFrame.h"
25 #include "VuoText.h"
26 #include "VuoUrl.h"
27 
28 // FFMPEG
29 #pragma clang diagnostic push
30 #pragma clang diagnostic ignored "-Wdocumentation"
31 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
32 #include <libavcodec/avcodec.h>
33 #include <libavformat/avformat.h>
34 #include <libavutil/avutil.h>
35 #include <libswscale/swscale.h>
36 #include <string.h>
37 #include <libswresample/swresample.h>
38 #include <libavutil/opt.h>
39 #pragma clang diagnostic pop
40 
41 #include <sys/types.h> // for uint
42 #ifdef __cplusplus
43 }
44 #endif
45 
50 {
51 public:
53  static VuoFfmpegDecoder* Create(VuoUrl url);
54 
56  virtual ~VuoFfmpegDecoder();
58  virtual bool NextVideoFrame(VuoVideoFrame* frame);
60  virtual bool NextAudioFrame(VuoAudioFrame* audio);
62  virtual bool SeekToSecond(double second, VuoVideoFrame *frame);
64  bool ContainsAudio();
66  virtual double GetDuration();
69  virtual void SetPlaybackRate(double rate);
71  virtual double GetLastDecodedVideoTimeStamp();
73  virtual bool CanPlayAudio();
75  virtual unsigned int GetAudioChannelCount();
77  virtual bool IsReady() { return isReady; }
79  virtual double GetFrameRate();
80 
81 private:
82 
86  template<class T> struct LLNode
87  {
88  T data;
89  LLNode* next;
90  LLNode* previous;
91 
92  LLNode(T value)
93  {
94  data = value;
95  next = NULL;
96  previous = NULL;
97  }
98  };
99 
103  template<class T> struct LinkedList
104  {
105  LLNode<T>* first; // pointer to the first node in this list.
106  LLNode<T>* last; // pointer to the last node in the list
107 
108  void (*destructor)(T*);
109 
110  unsigned int _size; // how many nodes are in this list
111  unsigned int Count() { return _size; }
112 
113  LinkedList()
114  {
115  _size = 0;
116  first = NULL;
117  last = NULL;
118  destructor = NULL;
119  }
120 
121  ~LinkedList()
122  {
123  Clear();
124  }
125 
126  void Clear()
127  {
128  LLNode<T>* cur = first;
129 
130  while(cur)
131  {
132  if(destructor != NULL)
133  destructor(&cur->data);
134  LLNode<T>* tmp = cur;
135  cur = tmp->next;
136  delete(tmp);
137  }
138 
139  _size = 0;
140 
141  first = NULL;
142  last = NULL;
143  }
144 
145  void Add(T value)
146  {
147  LLNode<T>* node = new LLNode<T>(value);
148 
149  if( last )
150  {
151  node->previous = last;
152  last->next = node;
153  last = node;
154  }
155  else
156  {
157  first = node;
158  last = node;
159  }
160 
161  _size++;
162  }
163 
167  void Unshift(T value)
168  {
169  LLNode<T>* node = new LLNode<T>(value);
170 
171  if(first != NULL)
172  {
173  first->previous = node;
174  node->next = first;
175  first = node;
176  }
177  else
178  {
179  first = node;
180  last = node;
181  }
182 
183  _size++;
184  }
185 
186  void Remove(LLNode<T>* node)
187  {
188  if(node == NULL)
189  return;
190 
191  if(node->next)
192  {
193  if(node->previous)
194  {
195  node->previous->next = node->next;
196  node->next->previous = node->previous;
197  }
198  else
199  {
200  // was first node
201  node->next->previous = NULL;
202  first = node->next;
203  }
204  }
205  else
206  {
207  // was last node in list
208  if(node->previous)
209  {
210  last = node->previous;
211  node->previous->next = NULL;
212  }
213  // was only node in list
214  else
215  {
216  first = NULL;
217  last = NULL;
218  }
219  }
220 
221  _size--;
222  delete(node);
223  }
224 
228  bool Shift(T* value)
229  {
230  if(first != NULL)
231  {
232  *value = first->data;
233  LLNode<T>* tmp = first;
234 
235  if(tmp->next == NULL)
236  {
237  first = NULL;
238  last = NULL;
239  }
240  else
241  {
242  first = first->next;
243  }
244 
245  delete(tmp);
246  _size--;
247 
248  return true;
249  }
250  else
251  {
252  return false;
253  }
254  }
255 
259  bool Pop(T* value)
260  {
261  if(last != NULL)
262  {
263  *value = last->data;
264 
265  LLNode<T>* tmp = last;
266 
267  if(last->previous == NULL)
268  {
269  first = NULL;
270  last = NULL;
271  }
272  else
273  {
274  last = last->previous;
275  last->next = NULL;
276  }
277 
278  delete(tmp);
279  _size--;
280 
281  return true;
282  }
283 
284  return false;
285  }
286 
290  bool Peek(T* value)
291  {
292  if(first != NULL)
293  {
294  *value = first->data;
295  return true;
296  }
297  return false;
298  }
299 
300  bool PeekLast(T* value)
301  {
302  if(last != NULL)
303  {
304  *value = last->data;
305  return true;
306  }
307  return false;
308  }
309  };
310 
314  struct AudioFrame
315  {
316  unsigned int size;
317  unsigned int channels;
318  int64_t pts;
319  double timestamp;
320  uint8_t** samples;
321 
322  static void Delete(AudioFrame* frame)
323  {
324  for(int i = 0; i < frame->channels; i++)
325  free(frame->samples[i]);
326  free(frame->samples);
327  }
328  };
329 
330  struct VideoFrame
331  {
332  VuoImage image;
333  int64_t pts;
334  double timestamp;
335  double duration;
336 
337  static void Delete(VideoFrame* frame)
338  {
339  VuoRelease(frame->image);
340  }
341  };
342 
343  LinkedList<AudioFrame> audioFrames;
344  LinkedList<VideoFrame> videoFrames;
345  LinkedList<AVPacket> videoPackets;
346  LinkedList<AVPacket> audioPackets;
347 
348  struct VideoInfo
349  {
350  int64_t first_pts; // first pts value in video stream time
351  int64_t last_pts; // finish in video stream time
352  int64_t max_pts; // largest decoded pts in video stream time
353  int64_t duration; // duration in video stream time
354  };
355 
359  struct AVContainer
360  {
361  AVFormatContext* formatCtx;
362  AVCodecContext* videoCodecCtx;
363  AVCodecContext* audioCodecCtx;
364 
365  struct SwrContext *swr_ctx; // for resampling audio
366  int bytesPerAudioSample; // Size of an audio samples (eg, sizeof(float), sizeof(int), etc).
367 
368  // Stream contains information about the channel, ex time base and length.
369  int videoStreamIndex, audioStreamIndex;
370  AVStream* videoStream;
371  AVStream* audioStream;
372 
373  VideoInfo videoInfo;
374  VideoInfo audioInfo;
375 
376  bool seekUnavailable;
377  };
378 
379  AVContainer container;
380 
382  VuoUrl mVideoPath;
383 
386  double mPlaybackRate;
387 
388  int64_t lastDecodedVideoPts;
389  int64_t lastSentVideoPts;
390  int64_t lastDecodedAudioPts;
391  bool showedTimestampGapWarning;
392  bool showedSeekIgnoredWarning;
393 
394  double lastVideoTimestamp; // Last sent video timestamp in seconds, relative to 0 being start of movie (actual timestamp could be negative, or non-zero)
395  double lastAudioTimestamp; // Last sent audio timestamp in seconds.
396 
397  // Audio sync cumulative difference in last decoded timestamp.
398  double audio_diff_cum;
399  double audio_diff_avg_coef;
400  // The threshold at which to begin modifying returned audio sample arrays to better sync with video.
401  double audio_diff_threshold;
402  int audio_diff_avg_count;
403 
404  // If the playback rate is 1, enable audio
405  bool audioIsEnabled;
406 
407  // Holds decoded audio between extraction from frame and conversion to VuoAudioSamples.
408  uint8_t** audio_buf;
409 
410  // The size of a single channel of audio in audio_buf, set by DecodeAudio(). ( sampleCount * sizeof(double) )
411  unsigned int audio_buf_size;
412 
413  // the current index in audio_buff (per-channel) that is being copied to VuoAudioSamples
414  unsigned int audio_buf_index;
415 
416  // The numbder of audio channels.
417  uint audio_channels;
418 
419  // it can take more than one call to DecodeAudio() to extract all samples from an audio
420  // packet, so store it locally til done.
421  AVPacket audio_packet;
422  uint8_t *audio_pkt_data;
423  int audio_pkt_size;
424 
425  bool isReady = false;
426 
427  // Calls base-constructor, nothing else.
429 
430  // Prepare internal stuff for decoding.
431  bool Initialize() VuoWarnUnusedResult;
432 
433  // Initialize the video context
434  bool InitializeVideo(VuoFfmpegDecoder::AVContainer& container) VuoWarnUnusedResult;
435 
436  // Initialize the audio context
437  bool InitializeAudio(VuoFfmpegDecoder::AVContainer& container) VuoWarnUnusedResult;
438 
439  // Read information about starting and ending timestamp + duration for both container.videoInfo & container.audioInfo
440  bool InitializeVideoInfo() VuoWarnUnusedResult;
441 
442  // Advance the next packet and place in either video or audio queue.
443  bool NextPacket() VuoWarnUnusedResult;
444 
445  // Decode a frame of audio, and store the frames in audioFrames list
446  bool DecodeAudioFrame() VuoWarnUnusedResult;
447 
448  // Decode a frame of video, and store the frames in videoFrames list
449  bool DecodeVideoFrame() VuoWarnUnusedResult;
450 
451  // Decode a chunk of video frames prior to the current video timestamp.
452  bool DecodePreceedingVideoFrames() VuoWarnUnusedResult;
453 
454  // Grab the next frame from audioFrames, calling NextPacket & DecodeAudio as necessary.
455  bool FillAudioBuffer() VuoWarnUnusedResult;
456 
457  // Seek to presentation timestamp.
458  void SeekToPts(int64_t pts, VuoVideoFrame *frame);
459 
462  bool seeking;
463 
464  // After av_seek, use this to step the decoded frames to a more exact position
465  bool StepVideoFrame(int64_t pts, VuoVideoFrame *frame) VuoWarnUnusedResult;
466  bool StepAudioFrame(int64_t pts) VuoWarnUnusedResult;
467 
468  void ClearAudioBuffer();
469 
479  const double MAX_AUDIO_LEAD = .022;
480 
482  const double MAX_AUDIO_LATENCY = -.045;
483 
484  const unsigned int MAX_FRAME_SKIP = 1;
485 
487  double AudioOffset();
488 };