Welcome to mirror list, hosted at ThFree Co, Russian Federation.

LAVAudio.h « LAVAudio « decoder - github.com/mpc-hc/LAVFilters.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 65c5437c3442b99e374f14edd7cfcb9c2c388f3e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
/*
 *      Copyright (C) 2010-2017 Hendrik Leppkes
 *      http://www.1f0.de
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#pragma once

#include "LAVAudioSettings.h"
#include "FloatingAverage.h"
#include "Media.h"
#include "BitstreamParser.h"
#include "PostProcessor.h"

#include "ISpecifyPropertyPages2.h"
#include "BaseTrayIcon.h"

//////////////////// Configuration //////////////////////////

// Buffer Size for decoded PCM: 1s of 192kHz 32-bit with 8 channels
// 192000 (Samples) * 4 (Bytes per Sample) * 8 (channels)
#define LAV_AUDIO_BUFFER_SIZE 6144000

// Maximum Durations (in reference time)
// 10ms (DTS has 10.6667 ms samples, don't want to queue them up)
#define PCM_BUFFER_MAX_DURATION 100000
// 6ms
#define PCM_BUFFER_MIN_DURATION 60000

// Maximum desync that we attribute to jitter before re-syncing (10ms)
#define MAX_JITTER_DESYNC 100000i64

//////////////////// End Configuration //////////////////////

#define AV_CODEC_ID_PCM_SxxBE (AVCodecID)0x19001
#define AV_CODEC_ID_PCM_SxxLE (AVCodecID)0x19002
#define AV_CODEC_ID_PCM_UxxBE (AVCodecID)0x19003
#define AV_CODEC_ID_PCM_UxxLE (AVCodecID)0x19004
#define AV_CODEC_ID_PCM_QTRAW (AVCodecID)0x19005

#define LAVC_AUDIO_REGISTRY_KEY L"Software\\LAV\\Audio"
#define LAVC_AUDIO_REGISTRY_KEY_FORMATS L"Software\\LAV\\Audio\\Formats"
#define LAVC_AUDIO_LOG_FILE     L"LAVAudio.txt"

struct WAVEFORMATEX_HDMV_LPCM;

struct BufferDetails {
  GrowableArray<BYTE>   *bBuffer        = nullptr;         // PCM Buffer
  LAVAudioSampleFormat  sfFormat        = SampleFormat_16; // Sample Format
  WORD                  wBitsPerSample  = 0;               // Bits per sample
  DWORD                 dwSamplesPerSec = 0;               // Samples per second
  unsigned              nSamples        = 0;               // Samples in the buffer (every sample is sizeof(sfFormat) * nChannels in the buffer)
  WORD                  wChannels       = 0;               // Number of channels
  DWORD                 dwChannelMask   = 0;               // channel mask
  REFERENCE_TIME        rtStart         = AV_NOPTS_VALUE;  // Start Time of the buffer
  BOOL                  bPlanar         = FALSE;           // Planar (not used)


  BufferDetails() {
    bBuffer = new GrowableArray<BYTE>();
  };
  ~BufferDetails() {
    delete bBuffer;
  }
};

struct DTSDecoder;

class __declspec(uuid("E8E73B6B-4CB3-44A4-BE99-4F7BCB96E491")) CLAVAudio : public CTransformFilter, public ISpecifyPropertyPages2,
                                                                           public ILAVAudioSettings, public ILAVAudioSettingsMPCHCCustom,
                                                                           public ILAVAudioStatus
{
public:
  CLAVAudio(LPUNKNOWN pUnk, HRESULT* phr);
  ~CLAVAudio();

  static void CALLBACK StaticInit(BOOL bLoading, const CLSID *clsid);

  // IUnknown
  DECLARE_IUNKNOWN;
  STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv);

  // ISpecifyPropertyPages2
  STDMETHODIMP GetPages(CAUUID *pPages);
  STDMETHODIMP CreatePage(const GUID& guid, IPropertyPage** ppPage);

  // ILAVAudioSettings
  STDMETHODIMP SetRuntimeConfig(BOOL bRuntimeConfig);
  STDMETHODIMP GetDRC(BOOL *pbDRCEnabled, int *piDRCLevel);
  STDMETHODIMP SetDRC(BOOL bDRCEnabled, int iDRCLevel);
  STDMETHODIMP_(BOOL) GetFormatConfiguration(LAVAudioCodec aCodec);
  STDMETHODIMP SetFormatConfiguration(LAVAudioCodec aCodec, BOOL bEnabled);
  STDMETHODIMP_(BOOL) GetBitstreamConfig(LAVBitstreamCodec bsCodec);
  STDMETHODIMP SetBitstreamConfig(LAVBitstreamCodec bsCodec, BOOL bEnabled);
  STDMETHODIMP_(BOOL) GetDTSHDFraming();
  STDMETHODIMP SetDTSHDFraming(BOOL bHDFraming);
  STDMETHODIMP_(BOOL) GetAutoAVSync();
  STDMETHODIMP SetAutoAVSync(BOOL bAutoSync);
  STDMETHODIMP_(BOOL) GetOutputStandardLayout();
  STDMETHODIMP SetOutputStandardLayout(BOOL bStdLayout);
  STDMETHODIMP_(BOOL) GetExpandMono();
  STDMETHODIMP SetExpandMono(BOOL bExpandMono);
  STDMETHODIMP_(BOOL) GetExpand61();
  STDMETHODIMP SetExpand61(BOOL bExpand61);
  STDMETHODIMP_(BOOL) GetAllowRawSPDIFInput();
  STDMETHODIMP SetAllowRawSPDIFInput(BOOL bAllow);
  STDMETHODIMP_(BOOL) GetSampleFormat(LAVAudioSampleFormat format);
  STDMETHODIMP SetSampleFormat(LAVAudioSampleFormat format, BOOL bEnabled);
  STDMETHODIMP GetAudioDelay(BOOL *pbEnabled, int *pDelay);
  STDMETHODIMP SetAudioDelay(BOOL bEnabled, int delay);
  STDMETHODIMP SetMixingEnabled(BOOL bEnabled);
  STDMETHODIMP_(BOOL) GetMixingEnabled();
  STDMETHODIMP SetMixingLayout(DWORD dwLayout);
  STDMETHODIMP_(DWORD) GetMixingLayout();
  STDMETHODIMP SetMixingFlags(DWORD dwFlags);
  STDMETHODIMP_(DWORD) GetMixingFlags();
  STDMETHODIMP SetMixingMode(LAVAudioMixingMode mixingMode);
  STDMETHODIMP_(LAVAudioMixingMode) GetMixingMode();
  STDMETHODIMP SetMixingLevels(DWORD dwCenterLevel, DWORD dwSurroundLevel, DWORD dwLFELevel);
  STDMETHODIMP GetMixingLevels(DWORD *dwCenterLevel, DWORD *dwSurroundLevel, DWORD *dwLFELevel);
  STDMETHODIMP SetTrayIcon(BOOL bEnabled);
  STDMETHODIMP_(BOOL) GetTrayIcon();
  STDMETHODIMP SetSampleConvertDithering(BOOL bEnabled);
  STDMETHODIMP_(BOOL) GetSampleConvertDithering();
  STDMETHODIMP SetSuppressFormatChanges(BOOL bEnabled);
  STDMETHODIMP_(BOOL) GetSuppressFormatChanges();
  STDMETHODIMP SetOutput51LegacyLayout(BOOL b51Legacy);
  STDMETHODIMP_(BOOL) GetOutput51LegacyLayout();

  // ILAVAudioSettingsMPCHCCustom
  STDMETHODIMP SetPropertyPageCallback(HRESULT (*fpPropPageCallback)(IBaseFilter* pFilter));

  // ILAVAudioStatus
  STDMETHODIMP_(BOOL) IsSampleFormatSupported(LAVAudioSampleFormat sfCheck);
  STDMETHODIMP GetDecodeDetails(const char **pCodec, const char **pDecodeFormat, int *pnChannels, int *pSampleRate, DWORD *pChannelMask);
  STDMETHODIMP GetOutputDetails(const char **pOutputFormat, int *pnChannels, int *pSampleRate, DWORD *pChannelMask);
  STDMETHODIMP EnableVolumeStats();
  STDMETHODIMP DisableVolumeStats();
  STDMETHODIMP GetChannelVolumeAverage(WORD nChannel, float *pfDb);

  // CTransformFilter
  HRESULT CheckInputType(const CMediaType* mtIn);
  HRESULT CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut);
  HRESULT DecideBufferSize(IMemAllocator * pAllocator, ALLOCATOR_PROPERTIES *pprop);
  HRESULT GetMediaType(int iPosition, CMediaType *pMediaType);

  HRESULT Receive(IMediaSample *pIn);

  STDMETHODIMP JoinFilterGraph(IFilterGraph * pGraph, LPCWSTR pName);

  // Optional Overrides
  HRESULT CheckConnect(PIN_DIRECTION dir, IPin *pPin);
  HRESULT SetMediaType(PIN_DIRECTION dir, const CMediaType *pmt);

  HRESULT EndOfStream();
  HRESULT BeginFlush();
  HRESULT EndFlush();
  HRESULT NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate);

  HRESULT BreakConnect(PIN_DIRECTION Dir);

public:
  // Pin Configuration
  const static AMOVIESETUP_MEDIATYPE    sudPinTypesIn[];
  const static UINT                     sudPinTypesInCount;
  const static AMOVIESETUP_MEDIATYPE    sudPinTypesOut[];
  const static UINT                     sudPinTypesOutCount;

private:
  HRESULT LoadDefaults();
  HRESULT ReadSettings(HKEY rootKey);
  HRESULT LoadSettings();
  HRESULT SaveSettings();

  STDMETHODIMP CreateTrayIcon();

  HRESULT ffmpeg_init(AVCodecID codec, const void *format, GUID format_type, DWORD formatlen);
  void ffmpeg_shutdown();

  CMediaType CreateMediaType(LAVAudioSampleFormat outputFormat, DWORD nSamplesPerSec, WORD nChannels, DWORD dwChannelMask, WORD wBitsPerSample = 0) const;
  HRESULT ReconnectOutput(long cbBuffer, CMediaType& mt);
  HRESULT ProcessBuffer(IMediaSample *pMediaSample, BOOL bEOF = FALSE);
  HRESULT Decode(const BYTE *p, int buffsize, int &consumed, HRESULT *hrDeliver, IMediaSample *pMediaSample);
  HRESULT PostProcess(BufferDetails *buffer);
  HRESULT GetDeliveryBuffer(IMediaSample **pSample, BYTE **pData);

  HRESULT QueueOutput(BufferDetails &buffer);
  HRESULT FlushOutput(BOOL bDeliver = TRUE);
  HRESULT FlushDecoder();

  HRESULT PerformFlush();
  HRESULT Deliver(BufferDetails &buffer);

  void CreateBDLPCMHeader(BYTE *pBuf, const WAVEFORMATEX_HDMV_LPCM *wfex_lpcm) const;
  void CreateDVDLPCMHeader(BYTE *pBuf, const WAVEFORMATEX *wfex) const;
  HRESULT ParseRealAudioHeader(const BYTE *extra, const size_t extralen);
  HRESULT ResyncMPEGAudio();

  void UpdateVolumeStats(const BufferDetails &buffer);

  BOOL IsBitstreaming(AVCodecID codec);
  HRESULT InitBitstreaming();
  HRESULT ShutdownBitstreaming();
  static int BSWriteBuffer(void *opaque, uint8_t *buf, int buf_size);

  HRESULT CreateBitstreamContext(AVCodecID codec, WAVEFORMATEX *wfe);
  HRESULT UpdateBitstreamContext();
  HRESULT FreeBitstreamContext();

  HRESULT Bitstream(const BYTE *p, int buffsize, int &consumed, HRESULT *hrDeliver);
  HRESULT DeliverBitstream(AVCodecID codec, const BYTE *buffer, DWORD dwSize, DWORD dwFrameSize, REFERENCE_TIME rtStartInput, REFERENCE_TIME rtStopInput);

  CMediaType CreateBitstreamMediaType(AVCodecID codec, DWORD dwSampleRate, BOOL bDTSHDOverride = FALSE);
  void ActivateDTSHDMuxing();

  HRESULT InitDTSDecoder();
  HRESULT FreeDTSDecoder();
  HRESULT FlushDTSDecoder(BOOL bReopen = FALSE);
  HRESULT DecodeDTS(const BYTE * const p, int buffsize, int &consumed, HRESULT *hrDeliver);
  int SafeDTSDecode(BYTE *pInput, int len, BYTE *pOutput, int unk1, int unk2, int *pBitdepth, int *pChannels, int *pCoreSampleRate, int *pUnk4, int *pHDSampleRate, int *pUnk5, int *pProfile);

  HRESULT CheckChannelLayoutConformity(DWORD dwLayout);
  HRESULT Create51Conformity(DWORD dwLayout);
  HRESULT Create61Conformity(DWORD dwLayout);
  HRESULT Create71Conformity(DWORD dwLayout);

  LAVAudioSampleFormat GetBestAvailableSampleFormat(LAVAudioSampleFormat inFormat, int *bits = NULL, BOOL bNoFallback = FALSE);
  HRESULT Truncate32Buffer(BufferDetails *buffer);
  HRESULT PadTo32(BufferDetails *buffer);

  HRESULT PerformAVRProcessing(BufferDetails *buffer);

private:
  AVCodecID             m_nCodecId = AV_CODEC_ID_NONE;
  AVCodec              *m_pAVCodec = nullptr;
  AVCodecContext       *m_pAVCtx   = nullptr;
  AVCodecParserContext *m_pParser  = nullptr;
  AVFrame              *m_pFrame   = nullptr;

  BOOL                 m_bFlushing      = FALSE;
  BOOL                 m_bDiscontinuity = FALSE;
  REFERENCE_TIME       m_rtStart        = 0;
  double               m_dStartOffset   = 0.0;
  double               m_dRate          = 1.0;

  REFERENCE_TIME       m_rtStartInput      = AV_NOPTS_VALUE;   // rtStart of the current input package
  REFERENCE_TIME       m_rtStopInput       = AV_NOPTS_VALUE;   // rtStop of the current input package
  REFERENCE_TIME       m_rtStartInputCache = AV_NOPTS_VALUE;   // rtStart of the last input package
  REFERENCE_TIME       m_rtStopInputCache  = AV_NOPTS_VALUE;   // rtStop of the last input package
  REFERENCE_TIME       m_rtBitstreamCache  = AV_NOPTS_VALUE;   // Bitstreaming time cache
  BOOL                 m_bUpdateTimeCache  = TRUE;

  GrowableArray<BYTE>  m_buff;                                 // Input Buffer
  LAVAudioSampleFormat m_DecodeFormat      = SampleFormat_16;
  LAVAudioSampleFormat m_MixingInputFormat = SampleFormat_None;
  LAVAudioSampleFormat m_FallbackFormat    = SampleFormat_None;
  DWORD                m_dwOverrideMixer   = 0;

  int                  m_bHasVideo              = -1;

  AVAudioResampleContext *m_avrContext          = nullptr;
  LAVAudioSampleFormat m_sfRemixFormat          = SampleFormat_None;
  DWORD                m_dwRemixLayout          = 0;
  BOOL                 m_bAVResampleFailed      = FALSE;
  BOOL                 m_bMixingSettingsChanged = FALSE;

  // Settings
  struct AudioSettings {
    BOOL TrayIcon;
    BOOL DRCEnabled;
    int DRCLevel;
    BOOL bFormats[Codec_AudioNB];
    BOOL bBitstream[Bitstream_NB];
    BOOL DTSHDFraming;
    BOOL AutoAVSync;
    BOOL ExpandMono;
    BOOL Expand61;
    BOOL OutputStandardLayout;
    BOOL Output51Legacy;
    BOOL AllowRawSPDIF;
    BOOL bSampleFormats[SampleFormat_NB];
    BOOL SampleConvertDither;
    BOOL AudioDelayEnabled;
    int  AudioDelay;

    BOOL MixingEnabled;
    DWORD MixingLayout;
    DWORD MixingFlags;
    DWORD MixingMode;
    DWORD MixingCenterLevel;
    DWORD MixingSurroundLevel;
    DWORD MixingLFELevel;

    BOOL SuppressFormatChanges;
  } m_settings;
  BOOL                m_bRuntimeConfig = FALSE;

  BOOL                m_bVolumeStats   = FALSE;    // Volume Stats gathering enabled
  FloatingAverage<float> m_faVolume[8];            // Floating Average for volume (8 channels)

  BOOL                m_bQueueResync     = FALSE;
  BOOL                m_bResyncTimestamp = FALSE;
  BOOL                m_bNeedSyncpoint   = FALSE;
  BOOL                m_bJustFlushed     = TRUE;
  BufferDetails       m_OutputQueue;

  AVIOContext        *m_avioBitstream = nullptr;
  AVFormatContext    *m_avBSContext   = nullptr;
  GrowableArray<BYTE> m_bsOutput;
  BOOL                m_bBitStreamingSettingsChanged = FALSE;

  BOOL                m_bDTSHD                       = FALSE;
  BOOL                m_bForceDTSCore                = FALSE;
  CBitstreamParser    m_bsParser;
  BOOL                m_bFindDTSInPCM                = FALSE;
  BOOL                m_bDVDPlayback                 = FALSE;
  BOOL                m_bMPEGAudioResync             = FALSE;

  FloatingAverage<REFERENCE_TIME> m_faJitter{50};
  REFERENCE_TIME      m_JitterLimit = MAX_JITTER_DESYNC;

  HMODULE             m_hDllExtraDecoder    = nullptr;
  DTSDecoder          *m_pDTSDecoderContext = nullptr;
  unsigned            m_DTSBitDepth         = 0;
  unsigned            m_DTSDecodeChannels   = 0;

  DWORD               m_DecodeLayout            = 0;
  DWORD               m_DecodeLayoutSanified    = 0;
  DWORD               m_MixingInputLayout       = 0;
  BOOL                m_bChannelMappingRequired = FALSE;

  DWORD               m_SuppressLayout          = 0;

  ExtendedChannelMap  m_ChannelMap;
  int                 m_ChannelMapOutputChannels = 0;
  DWORD               m_ChannelMapOutputLayout   = 0;

  struct {
    int flavor;
    int coded_frame_size;
    int audio_framesize;
    int sub_packet_h;
    int sub_packet_size;
    unsigned int deint_id;
  } m_raData;

  CBaseTrayIcon *m_pTrayIcon = nullptr;
  HRESULT (*m_fpPropPageCallback)(IBaseFilter* pFilter) = nullptr;
};