1/**********************************************************************
2
3  Audacity: A Digital Audio Editor
4
5  AVFormatContextWrapperImpl.inl
6
7  Dmitry Vedenko
8
9**********************************************************************/
10
11//! Some checks for correct overlaying.
12// There is no AVDictionaryWrapper.inl, so put it here
13static_assert(
14   sizeof(AudacityAVDictionaryEntry) == sizeof(AVDictionaryEntry) &&
15   offsetof(AudacityAVDictionaryEntry, key) == offsetof(AVDictionaryEntry, key)
16      &&
17   offsetof(AudacityAVDictionaryEntry, value) == offsetof(AVDictionaryEntry,  value),
18   "AudacityAVDictionaryEntry does not safely overlay AVDictionaryEntry"
19);
20
21//! More sanity checks of macro constants
22static_assert(
23   AV_DICT_MATCH_CASE == DICT_MATCH_CASE
24   && AV_DICT_IGNORE_SUFFIX == DICT_IGNORE_SUFFIX
25   && AV_NOPTS_VALUE == AUDACITY_AV_NOPTS_VALUE
26   && AV_TIME_BASE == AUDACITY_AV_TIME_BASE
27   && FF_QP2LAMBDA == AUDACITY_FF_QP2LAMBDA
28   && FF_PROFILE_AAC_LOW == AUDACITY_FF_PROFILE_AAC_LOW
29   && AVFMT_NOFILE == AUDACITY_AVFMT_NOFILE
30   && AVFMT_GLOBALHEADER == AUDACITY_AVFMT_GLOBALHEADER
31   && FF_COMPLIANCE_EXPERIMENTAL == AUDACITY_FF_COMPLIANCE_EXPERIMENTAL
32   && AV_SAMPLE_FMT_U8 == static_cast<int>(AUDACITY_AV_SAMPLE_FMT_U8)
33   && AV_SAMPLE_FMT_U8P == static_cast<int>(AUDACITY_AV_SAMPLE_FMT_U8P)
34   && AV_SAMPLE_FMT_U8P == static_cast<int>(AUDACITY_AV_SAMPLE_FMT_U8P)
35   && AV_SAMPLE_FMT_S16P == static_cast<int>(AUDACITY_AV_SAMPLE_FMT_S16P)
36   && AV_SAMPLE_FMT_S32 == static_cast<int>(AUDACITY_AV_SAMPLE_FMT_S32)
37   && AV_SAMPLE_FMT_S32P == static_cast<int>(AUDACITY_AV_SAMPLE_FMT_S32P)
38   && AV_SAMPLE_FMT_FLT == static_cast<int>(AUDACITY_AV_SAMPLE_FMT_FLT)
39   && AV_SAMPLE_FMT_FLTP == static_cast<int>(AUDACITY_AV_SAMPLE_FMT_FLTP)
40,
41   "FFmpeg constants don't match"
42);
43
44class AVFormatContextWrapperImpl : public AVFormatContextWrapper
45{
46public:
47   AVFormatContextWrapperImpl(const FFmpegFunctions& ffmpeg)
48      : AVFormatContextWrapper(ffmpeg)
49   {
50      mAVFormatContext = mFFmpeg.avformat_alloc_context();
51   }
52
53   AVInputFormat* GetIFormat() const noexcept override
54   {
55      if (mAVFormatContext != nullptr)
56         return mAVFormatContext->iformat;
57
58      return {};
59   }
60
61   AVOutputFormat* GetOFormat() const noexcept override
62   {
63      if (mAVFormatContext != nullptr)
64         return mAVFormatContext->oformat;
65
66      return {};
67   }
68
69   void SetOutputFormat(std::unique_ptr<AVOutputFormatWrapper> oformat) noexcept override
70   {
71      if (mAVFormatContext != nullptr)
72      {
73         mAVFormatContext->oformat = oformat->GetWrappedValue();
74         mOutputFormat = std::move(oformat);
75      }
76   }
77
78   AVIOContextWrapper* GetAVIOContext() const noexcept override
79   {
80      return mAVIOContext.get();
81   }
82
83   void SetAVIOContext(std::unique_ptr<AVIOContextWrapper> pb) noexcept override
84   {
85      if (mAVFormatContext != nullptr)
86      {
87         mAVIOContext = std::move(pb);
88         mAVFormatContext->pb = mAVIOContext->GetWrappedValue();
89      }
90   }
91
92   int GetCtxFlags() const noexcept override
93   {
94      if (mAVFormatContext != nullptr)
95         return mAVFormatContext->ctx_flags;
96
97      return {};
98   }
99
100   unsigned int GetStreamsCount() const noexcept override
101   {
102      if (mAVFormatContext != nullptr)
103         return mAVFormatContext->nb_streams;
104
105      return {};
106   }
107
108   const AVFormatContextWrapper::StreamsList& GetStreams() const noexcept override
109   {
110      return mStreams;
111   }
112
113   const char* GetFilename() const noexcept override
114   {
115      if (mAVFormatContext != nullptr)
116         return mAVFormatContext->filename;
117
118      return {};
119   }
120
121   void SetFilename(const char* filename) noexcept override
122   {
123      if (mAVFormatContext == nullptr)
124         return;
125
126      const size_t len =
127         std::min(sizeof(mAVFormatContext->filename) - 1, std::strlen(filename));
128
129      std::copy(filename, filename + len, mAVFormatContext->filename);
130
131      mAVFormatContext->filename[len] = '\0';
132   }
133
134   int64_t GetStartTime() const noexcept override
135   {
136      if (mAVFormatContext != nullptr)
137         return mAVFormatContext->start_time;
138
139      return {};
140   }
141
142   int64_t GetDuration() const noexcept override
143   {
144      if (mAVFormatContext != nullptr)
145         return mAVFormatContext->duration;
146
147      return {};
148   }
149
150   int GetBitRate() const noexcept override
151   {
152      if (mAVFormatContext != nullptr)
153         // May truncate int64_t to int.  But who uses such high rates, really?
154         return mAVFormatContext->bit_rate;
155
156      return {};
157   }
158
159   void SetBitRate(int bit_rate) noexcept override
160   {
161      if (mAVFormatContext != nullptr)
162         mAVFormatContext->bit_rate = bit_rate;
163   }
164
165   unsigned int GetPacketSize() const noexcept override
166   {
167      if (mAVFormatContext != nullptr)
168         return mAVFormatContext->packet_size;
169
170      return {};
171   }
172
173   void SetPacketSize(unsigned int packet_size) noexcept override
174   {
175      if (mAVFormatContext != nullptr)
176         mAVFormatContext->packet_size = packet_size;
177   }
178
179   int GetMaxDelay() const noexcept override
180   {
181      if (mAVFormatContext != nullptr)
182         return mAVFormatContext->max_delay;
183
184      return {};
185   }
186
187   void SetMaxDelay(int max_delay) noexcept override
188   {
189      if (mAVFormatContext != nullptr)
190         mAVFormatContext->max_delay = max_delay;
191   }
192
193   int GetFlags() const noexcept override
194   {
195      if (mAVFormatContext != nullptr)
196         return mAVFormatContext->flags;
197
198      return {};
199   }
200
201   void SetFlags(int flags) noexcept override
202   {
203      if (mAVFormatContext != nullptr)
204         mAVFormatContext->flags = flags;
205   }
206
207   unsigned int GetProbeSize() const noexcept override
208   {
209      if (mAVFormatContext != nullptr)
210         return mAVFormatContext->probesize;
211
212      return {};
213   }
214
215   void SetProbeSize(unsigned int probesize) noexcept override
216   {
217      if (mAVFormatContext != nullptr)
218         mAVFormatContext->probesize = probesize;
219   }
220
221   int GetMaxAnalyzeDuration() const noexcept override
222   {
223      if (mAVFormatContext != nullptr)
224         return mAVFormatContext->max_analyze_duration;
225
226      return {};
227   }
228
229   void SetMaxAnalyzeDuration(int max_analyze_duration) noexcept override
230   {
231      if (mAVFormatContext != nullptr)
232         mAVFormatContext->max_analyze_duration = max_analyze_duration;
233   }
234
235   AVCodecIDFwd GetAudioCodecId() const noexcept override
236   {
237      if (mAVFormatContext != nullptr)
238         return mAVFormatContext->audio_codec_id;
239
240      return {};
241   }
242
243   void SetAudioCodecId(AVCodecIDFwd audio_codec_id) noexcept override
244   {
245      if (mAVFormatContext != nullptr)
246         mAVFormatContext->audio_codec_id = static_cast<AVCodecID>(audio_codec_id);
247   }
248
249   unsigned int GetMaxIndexSize() const noexcept override
250   {
251      if (mAVFormatContext != nullptr)
252         return mAVFormatContext->max_index_size;
253
254      return {};
255   }
256
257   void SetMaxIndexSize(unsigned int max_index_size) noexcept override
258   {
259      if (mAVFormatContext != nullptr)
260         mAVFormatContext->max_index_size = max_index_size;
261   }
262
263   AVDictionaryWrapper GetMetadata() const noexcept override
264   {
265      if (mAVFormatContext != nullptr)
266         return AVDictionaryWrapper(mFFmpeg, mAVFormatContext->metadata);
267
268      return AVDictionaryWrapper(mFFmpeg);
269   }
270
271   void SetMetadata(AVDictionaryWrapper metadata) noexcept override
272   {
273      if (mAVFormatContext == nullptr)
274         return;
275
276      if (mAVFormatContext->metadata != nullptr)
277         mFFmpeg.av_dict_free(&mAVFormatContext->metadata);
278
279      // This Release() doesn't leak:
280      /* */https://ffmpeg.org/doxygen/2.8/structAVFormatContext.html#a3019a56080ed2e3297ff25bc2ff88adf */
281      mAVFormatContext->metadata = metadata.Release();
282   }
283
284   int64_t GetStartTimeRealtime() const noexcept override
285   {
286      if (mAVFormatContext != nullptr)
287         return mAVFormatContext->start_time_realtime;
288
289      return {};
290   }
291
292   void SetStartTimeRealtime(int64_t start_time_realtime) noexcept override
293   {
294      if (mAVFormatContext != nullptr)
295         mAVFormatContext->start_time_realtime = start_time_realtime;
296   }
297
298   int GetFpsProbeSize() const noexcept override
299   {
300      if (mAVFormatContext != nullptr)
301         return mAVFormatContext->fps_probe_size;
302
303      return {};
304   }
305
306   void SetFpsProbeSize(int fps_probe_size) noexcept override
307   {
308      if (mAVFormatContext != nullptr)
309         mAVFormatContext->fps_probe_size = fps_probe_size;
310   }
311
312   int GetErrorRecognition() const noexcept override
313   {
314      if (mAVFormatContext != nullptr)
315         return mAVFormatContext->error_recognition;
316
317      return {};
318   }
319
320   void SetErrorRecognition(int error_recognition) noexcept override
321   {
322      if (mAVFormatContext != nullptr)
323         mAVFormatContext->error_recognition = error_recognition;
324   }
325
326   int64_t GetMaxInterleaveDelta() const noexcept override
327   {
328      if (mAVFormatContext != nullptr)
329         return mAVFormatContext->max_interleave_delta;
330
331      return {};
332   }
333
334   void SetMaxInterleaveDelta(int64_t max_interleave_delta) noexcept override
335   {
336      if (mAVFormatContext != nullptr)
337         mAVFormatContext->max_interleave_delta = max_interleave_delta;
338   }
339
340   int GetStrictStdCompliance() const noexcept override
341   {
342      if (mAVFormatContext != nullptr)
343         return mAVFormatContext->strict_std_compliance;
344
345      return {};
346   }
347
348   void SetStrictStdCompliance(int strict_std_compliance) noexcept override
349   {
350      if (mAVFormatContext != nullptr)
351         mAVFormatContext->strict_std_compliance = strict_std_compliance;
352   }
353
354   int GetAudioPreload() const noexcept override
355   {
356      if (mAVFormatContext != nullptr)
357         return mAVFormatContext->audio_preload;
358
359      return {};
360   }
361
362   void SetAudioPreload(int audio_preload) noexcept override
363   {
364      if (mAVFormatContext != nullptr)
365         mAVFormatContext->audio_preload = audio_preload;
366   }
367
368   int GetMaxChunkDuration() const noexcept override
369   {
370      if (mAVFormatContext != nullptr)
371         return mAVFormatContext->max_chunk_duration;
372
373      return {};
374   }
375
376   void SetMaxChunkDuration(int max_chunk_duration) noexcept override
377   {
378      if (mAVFormatContext != nullptr)
379         mAVFormatContext->max_chunk_duration = max_chunk_duration;
380   }
381
382   int GetMaxChunkSize() const noexcept override
383   {
384      if (mAVFormatContext != nullptr)
385         return mAVFormatContext->max_chunk_size;
386
387      return {};
388   }
389
390   void SetMaxChunkSize(int max_chunk_size) noexcept override
391   {
392      if (mAVFormatContext != nullptr)
393         mAVFormatContext->max_chunk_size = max_chunk_size;
394   }
395
396   int GetUseWallclockAsTimestamps() const noexcept override
397   {
398      if (mAVFormatContext != nullptr)
399         return mAVFormatContext->use_wallclock_as_timestamps;
400
401      return {};
402   }
403
404   void SetUseWallclockAsTimestamps(
405      int use_wallclock_as_timestamps) noexcept override
406   {
407      if (mAVFormatContext != nullptr)
408         mAVFormatContext->use_wallclock_as_timestamps = use_wallclock_as_timestamps;
409   }
410
411   int GetAvoidNegativeTs() const noexcept override
412   {
413      if (mAVFormatContext != nullptr)
414         return mAVFormatContext->avoid_negative_ts;
415
416      return {};
417   }
418
419   void SetAvoidNegativeTs(int avoid_negative_ts) noexcept override
420   {
421      if (mAVFormatContext != nullptr)
422         mAVFormatContext->avoid_negative_ts = avoid_negative_ts;
423   }
424
425   int GetAvioFlags() const noexcept override
426   {
427      if (mAVFormatContext != nullptr)
428         return mAVFormatContext->avio_flags;
429
430      return {};
431   }
432
433   void SetAvioFlags(int avio_flags) noexcept override
434   {
435      if (mAVFormatContext != nullptr)
436         mAVFormatContext->avio_flags = avio_flags;
437   }
438
439   int64_t GetSkipInitialBytes() const noexcept override
440   {
441      if (mAVFormatContext != nullptr)
442         return mAVFormatContext->skip_initial_bytes;
443
444      return {};
445   }
446
447   void SetSkipInitialBytes(int64_t skip_initial_bytes) noexcept override
448   {
449      if (mAVFormatContext != nullptr)
450         mAVFormatContext->skip_initial_bytes = skip_initial_bytes;
451   }
452
453   unsigned int GetCorrectTsOverflow() const noexcept override
454   {
455      if (mAVFormatContext != nullptr)
456         return mAVFormatContext->correct_ts_overflow;
457
458      return {};
459   }
460
461   void SetCorrectTsOverflow(unsigned int correct_ts_overflow) noexcept override
462   {
463      if (mAVFormatContext != nullptr)
464         mAVFormatContext->correct_ts_overflow = correct_ts_overflow;
465   }
466
467   int GetSeek2any() const noexcept override
468   {
469      if (mAVFormatContext != nullptr)
470         return mAVFormatContext->seek2any;
471
472      return {};
473   }
474
475   void SetSeek2any(int seek2any) noexcept override
476   {
477      if (mAVFormatContext != nullptr)
478         mAVFormatContext->seek2any = seek2any;
479   }
480
481   int GetFlushPackets() const noexcept override
482   {
483      if (mAVFormatContext != nullptr)
484         return mAVFormatContext->flush_packets;
485
486      return {};
487   }
488
489   void SetFlushPackets(int flush_packets) noexcept override
490   {
491      if (mAVFormatContext != nullptr)
492         mAVFormatContext->flush_packets = flush_packets;
493   }
494
495   int GetProbeScore() const noexcept override
496   {
497      if (mAVFormatContext != nullptr)
498         return mAVFormatContext->probe_score;
499
500      return {};
501   }
502
503   int GetFormatProbeSize() const noexcept override
504   {
505      if (mAVFormatContext != nullptr)
506         return mAVFormatContext->format_probesize;
507
508      return {};
509   }
510
511   void SetFormatProbeSize(int format_probesize) noexcept override
512   {
513      if (mAVFormatContext != nullptr)
514         mAVFormatContext->format_probesize = format_probesize;
515   }
516
517   AVCodecWrapper* GetAudioCodec() const noexcept override
518   {
519      return mForcedAudioCodec.get();
520   }
521
522   void SetAudioCodec(std::unique_ptr<AVCodecWrapper> audio_codec) noexcept override
523   {
524      if (mAVFormatContext == nullptr)
525         return;
526
527      mAVFormatContext->audio_codec = audio_codec->GetWrappedValue();
528      mForcedAudioCodec = move(audio_codec);
529   }
530
531   void* GetOpaque() const noexcept override
532   {
533      if (mAVFormatContext != nullptr)
534         return mAVFormatContext->opaque;
535
536      return {};
537   }
538
539   void SetOpaque(void* opaque) noexcept override
540   {
541      if (mAVFormatContext != nullptr)
542         mAVFormatContext->opaque = opaque;
543   }
544
545   int64_t GetOutputTsOffset() const noexcept override
546   {
547      if (mAVFormatContext != nullptr)
548         return mAVFormatContext->output_ts_offset;
549
550      return {};
551   }
552
553   void SetOutputTsOffset(int64_t output_ts_offset) noexcept override
554   {
555      if (mAVFormatContext != nullptr)
556         mAVFormatContext->output_ts_offset = output_ts_offset;
557   }
558
559   void UpdateStreamList() noexcept override
560   {
561      mStreams.clear();
562
563      for (int i = 0; i < mAVFormatContext->nb_streams; ++i)
564         mStreams.emplace_back(mFFmpeg.CreateAVStreamWrapper(mAVFormatContext->streams[i]));
565   }
566};
567
568std::unique_ptr<AVFormatContextWrapper> CreateAVFormatContextWrapper (const FFmpegFunctions& ffmpeg)
569{
570   return std::make_unique<AVFormatContextWrapperImpl>(ffmpeg);
571}
572