1 // VirtualDub - Video processing and capture application
2 // Copyright (C) 1998-2007 Avery Lee
3 //
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 2 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 #include "stdafx.h"
19 #include <vfw.h>
20 #include <vd2/system/debug.h>
21 #include <vd2/system/log.h>
22 #include <vd2/system/error.h>
23 #include <vd2/system/math.h>
24 #include <vd2/Dita/resources.h>
25 #include "AVIReadHandler.h"
26 #include "Avisynth.h"
27
28 ///////////////////////////////////////////////////////////////////////////////
29
30 namespace {
31 enum { kVDST_AVIReadHandler = 2 };
32
33 enum {
34 kVDM_AvisynthDetected, // AVI: Avisynth detected. Extended error handling enabled.
35 kVDM_OpenDMLIndexDetected, // AVI: OpenDML hierarchical index detected on stream %d.
36 kVDM_IndexMissing, // AVI: Index not found or damaged -- reconstructing via file scan.
37 kVDM_InvalidChunkDetected, // AVI: Invalid chunk detected at %lld. Enabling aggressive recovery mode.
38 kVDM_StreamFailure, // AVI: Invalid block found at %lld -- disabling streaming.
39 kVDM_FixingBadSampleRate, // AVI: Stream %d has an invalid sample rate. Substituting %lu samples/sec as placeholder.
40 kVDM_PaletteChanges, // AVI: Palette changes detected. These are not currently supported -- color palette errors may appear in the output.
41 kVDM_InfoTruncated, // AVI: The text information chunk of type '%s' at %llx was not fully read because it was too long (%u bytes).
42 kVDM_NonZeroStart // AVI: Stream %u (%s) has a start position of %lld samples (%+lld ms). VirtualDub does not currently support a non-zero start time and the stream will be interpreted as starting from zero.
43 };
44
ConvertAVIStreamInfo(VDAVIStreamInfo & streamInfo,const AVISTREAMINFO & streamInfoW32)45 void ConvertAVIStreamInfo(VDAVIStreamInfo& streamInfo, const AVISTREAMINFO& streamInfoW32) {
46 streamInfo.fccType = streamInfoW32.fccType;
47 streamInfo.fccHandler = streamInfoW32.fccHandler;
48 streamInfo.dwFlags = streamInfoW32.dwFlags;
49 streamInfo.wPriority = streamInfoW32.wPriority;
50 streamInfo.wLanguage = streamInfoW32.wLanguage;
51 streamInfo.dwScale = streamInfoW32.dwScale;
52 streamInfo.dwRate = streamInfoW32.dwRate;
53 streamInfo.dwStart = streamInfoW32.dwStart;
54 streamInfo.dwLength = streamInfoW32.dwLength;
55 streamInfo.dwInitialFrames = streamInfoW32.dwInitialFrames;
56 streamInfo.dwSuggestedBufferSize = streamInfoW32.dwSuggestedBufferSize;
57 streamInfo.dwQuality = streamInfoW32.dwQuality;
58 streamInfo.dwSampleSize = streamInfoW32.dwSampleSize;
59 streamInfo.rcFrameLeft = (uint16)streamInfoW32.rcFrame.left;
60 streamInfo.rcFrameTop = (uint16)streamInfoW32.rcFrame.top;
61 streamInfo.rcFrameRight = (uint16)streamInfoW32.rcFrame.right;
62 streamInfo.rcFrameBottom = (uint16)streamInfoW32.rcFrame.bottom;
63 }
64 }
65
66 ///////////////////////////////////////////////////////////////////////////////
67
68 class AVIReadTunnelStream : public IAVIReadStream {
69 public:
70 AVIReadTunnelStream(IAVIReadHandler *, PAVISTREAM, IAvisynthClipInfo *pClipInfo);
71 ~AVIReadTunnelStream();
72
73 sint32 BeginStreaming(VDPosition lStart, VDPosition lEnd, long lRate);
74 sint32 EndStreaming();
75 sint32 Info(VDAVIStreamInfo *pasi);
76 bool IsKeyFrame(VDPosition lFrame);
77 sint32 Read(VDPosition lStart, long lSamples, void *lpBuffer, long cbBuffer, long *plBytes, long *plSamples);
78 VDPosition Start();
79 VDPosition End();
80 VDPosition PrevKeyFrame(VDPosition lFrame);
81 VDPosition NextKeyFrame(VDPosition lFrame);
82 VDPosition NearestKeyFrame(VDPosition lFrame);
83 sint32 FormatSize(VDPosition lFrame, long *plSize);
84 sint32 ReadFormat(VDPosition lFrame, void *pFormat, long *plSize);
85 bool isStreaming();
86 bool isKeyframeOnly();
getVBRInfo(double & bitrate_mean,double & bitrate_stddev,double & maxdev)87 bool getVBRInfo(double& bitrate_mean, double& bitrate_stddev, double& maxdev) { return false; }
88
getSampleBytePosition(VDPosition sample_num)89 sint64 getSampleBytePosition(VDPosition sample_num) { return -1; }
90
91 VDPosition TimeToPosition(VDTime timeInMicroseconds);
92 VDTime PositionToTime(VDPosition pos);
93
94 private:
95 IAvisynthClipInfo *const mpAvisynthClipInfo;
96 IAVIReadHandler *const parent;
97 const PAVISTREAM pas;
98 };
99
100 ///////////////////////////////////////////////////////////////////////////
101
AVIReadTunnelStream(IAVIReadHandler * _parent,PAVISTREAM _pas,IAvisynthClipInfo * pClipInfo)102 AVIReadTunnelStream::AVIReadTunnelStream(IAVIReadHandler *_parent, PAVISTREAM _pas, IAvisynthClipInfo *pClipInfo)
103 : mpAvisynthClipInfo(pClipInfo)
104 , parent(_parent)
105 , pas(_pas)
106 {
107 parent->AddRef();
108 }
109
~AVIReadTunnelStream()110 AVIReadTunnelStream::~AVIReadTunnelStream() {
111 pas->Release();
112 parent->Release();
113 }
114
BeginStreaming(VDPosition lStart,VDPosition lEnd,long lRate)115 sint32 AVIReadTunnelStream::BeginStreaming(VDPosition lStart, VDPosition lEnd, long lRate) {
116 LONG lStart32 = (LONG)lStart;
117 LONG lEnd32 = (LONG)lEnd;
118
119 if (lStart32 != lStart)
120 lStart32 = lStart < 0 ? (LONG)0x80000000 : (LONG)0x7FFFFFFF;
121 if (lEnd32 != lEnd)
122 lEnd32 = lEnd < 0 ? (LONG)0x80000000 : (LONG)0x7FFFFFFF;
123
124 return AVIStreamBeginStreaming(pas, lStart32, lEnd32, lRate);
125 }
126
EndStreaming()127 sint32 AVIReadTunnelStream::EndStreaming() {
128 return AVIStreamEndStreaming(pas);
129 }
130
Info(VDAVIStreamInfo * pasi)131 sint32 AVIReadTunnelStream::Info(VDAVIStreamInfo *pasi) {
132 AVISTREAMINFO streamInfoW32;
133 HRESULT hr = AVIStreamInfo(pas, &streamInfoW32, sizeof(streamInfoW32));
134
135 if (FAILED(hr))
136 return hr;
137
138 ConvertAVIStreamInfo(*pasi, streamInfoW32);
139 return S_OK;
140 }
141
IsKeyFrame(VDPosition lFrame)142 bool AVIReadTunnelStream::IsKeyFrame(VDPosition lFrame) {
143 LONG lFrame32 = (LONG)lFrame;
144
145 if (lFrame32 != lFrame)
146 lFrame32 = lFrame < 0 ? (LONG)0x80000000 : (LONG)0x7FFFFFFF;
147
148 return !!AVIStreamIsKeyFrame(pas, lFrame32);
149 }
150
Read(VDPosition lStart,long lSamples,void * lpBuffer,long cbBuffer,long * plBytes,long * plSamples)151 sint32 AVIReadTunnelStream::Read(VDPosition lStart, long lSamples, void *lpBuffer, long cbBuffer, long *plBytes, long *plSamples) {
152 HRESULT hr;
153
154 {
155 VDExternalCodeBracket(mpAvisynthClipInfo ? L"Avisynth" : L"An AVIFile input stream driver", __FILE__, __LINE__);
156 hr = AVIStreamRead(pas, (LONG)lStart, lSamples, lpBuffer, cbBuffer, plBytes, plSamples);
157 }
158
159 if (mpAvisynthClipInfo) {
160 const char *pszErr;
161
162 if (mpAvisynthClipInfo->GetError(&pszErr))
163 throw MyError("Avisynth read error:\n%s", pszErr);
164 }
165
166 return hr;
167 }
168
Start()169 VDPosition AVIReadTunnelStream::Start() {
170 return AVIStreamStart(pas);
171 }
172
End()173 VDPosition AVIReadTunnelStream::End() {
174 return AVIStreamEnd(pas);
175 }
176
PrevKeyFrame(VDPosition lFrame)177 VDPosition AVIReadTunnelStream::PrevKeyFrame(VDPosition lFrame) {
178 LONG lFrame32 = (LONG)lFrame;
179
180 if (lFrame32 != lFrame)
181 lFrame32 = lFrame < 0 ? (LONG)0x80000000 : (LONG)0x7FFFFFFF;
182
183 return AVIStreamPrevKeyFrame(pas, lFrame32);
184 }
185
NextKeyFrame(VDPosition lFrame)186 VDPosition AVIReadTunnelStream::NextKeyFrame(VDPosition lFrame) {
187 LONG lFrame32 = (LONG)lFrame;
188
189 if (lFrame32 != lFrame)
190 lFrame32 = lFrame < 0 ? (LONG)0x80000000 : (LONG)0x7FFFFFFF;
191
192 return AVIStreamNextKeyFrame(pas, lFrame32);
193 }
194
NearestKeyFrame(VDPosition lFrame)195 VDPosition AVIReadTunnelStream::NearestKeyFrame(VDPosition lFrame) {
196 LONG lFrame32 = (LONG)lFrame;
197
198 if (lFrame32 != lFrame)
199 lFrame32 = lFrame < 0 ? (LONG)0x80000000 : (LONG)0x7FFFFFFF;
200
201 return AVIStreamNearestKeyFrame(pas, lFrame32);
202 }
203
FormatSize(VDPosition lFrame,long * plSize)204 sint32 AVIReadTunnelStream::FormatSize(VDPosition lFrame, long *plSize) {
205 LONG lFrame32 = (LONG)lFrame;
206
207 if (lFrame32 != lFrame)
208 lFrame32 = lFrame < 0 ? (LONG)0x80000000 : (LONG)0x7FFFFFFF;
209
210 return AVIStreamFormatSize(pas, lFrame32, plSize);
211 }
212
ReadFormat(VDPosition lFrame,void * pFormat,long * plSize)213 sint32 AVIReadTunnelStream::ReadFormat(VDPosition lFrame, void *pFormat, long *plSize) {
214 LONG lFrame32 = (LONG)lFrame;
215
216 if (lFrame32 != lFrame)
217 lFrame32 = lFrame < 0 ? (LONG)0x80000000 : (LONG)0x7FFFFFFF;
218
219 return AVIStreamReadFormat(pas, lFrame32, pFormat, plSize);
220 }
221
isStreaming()222 bool AVIReadTunnelStream::isStreaming() {
223 return false;
224 }
225
isKeyframeOnly()226 bool AVIReadTunnelStream::isKeyframeOnly() {
227 return false;
228 }
229
TimeToPosition(VDTime timeInUs)230 VDPosition AVIReadTunnelStream::TimeToPosition(VDTime timeInUs) {
231 AVISTREAMINFO asi;
232 if (AVIStreamInfo(pas, &asi, sizeof asi))
233 return 0;
234
235 return VDRoundToInt64(timeInUs * (double)asi.dwRate / (double)asi.dwScale * (1.0 / 1000000.0));
236 }
237
PositionToTime(VDPosition pos)238 VDTime AVIReadTunnelStream::PositionToTime(VDPosition pos) {
239 AVISTREAMINFO asi;
240 if (AVIStreamInfo(pas, &asi, sizeof asi))
241 return 0;
242
243 return VDRoundToInt64(pos * (double)asi.dwScale / (double)asi.dwRate * 1000000.0);
244 }
245
246 ///////////////////////////////////////////////////////////////////////////
247
248 class AVIReadHandlerTunnelW32 : public IAVIReadHandler {
249 public:
250 AVIReadHandlerTunnelW32(const wchar_t *);
251 AVIReadHandlerTunnelW32(PAVIFILE);
252 ~AVIReadHandlerTunnelW32();
253
254 void AddRef();
255 void Release();
256 IAVIReadStream *GetStream(uint32 fccType, int lParam);
257 void EnableFastIO(bool);
258 bool isOptimizedForRealtime();
259 bool isStreaming();
260 bool isIndexFabricated();
261 bool AppendFile(const wchar_t *pszFile);
262 bool getSegmentHint(const char **ppszPath);
263 void GetTextInfo(tTextInfo& textInfo);
264 void GetTextInfoEncoding(int& codePage, int& countryCode, int& language, int& dialect);
265
266 private:
267 IAvisynthClipInfo *mpAvisynthClipInfo;
268 PAVIFILE mpAVIFile;
269 int mRefCount;
270 };
271
CreateAVIReadHandler(PAVIFILE paf)272 IAVIReadHandler *CreateAVIReadHandler(PAVIFILE paf) {
273 return new AVIReadHandlerTunnelW32(paf);
274 }
275
276 ///////////////////////////////////////////////////////////////////////////////
277
AVIReadHandlerTunnelW32(PAVIFILE pAVIFile)278 AVIReadHandlerTunnelW32::AVIReadHandlerTunnelW32(PAVIFILE pAVIFile)
279 : mpAvisynthClipInfo(nullptr)
280 , mpAVIFile(pAVIFile)
281 , mRefCount(1)
282 {
283 if (FAILED(mpAVIFile->QueryInterface(IID_IAvisynthClipInfo, (void **)&mpAvisynthClipInfo)))
284 mpAvisynthClipInfo = nullptr;
285 else {
286 const char *s;
287
288 if (mpAvisynthClipInfo->GetError(&s)) {
289 MyError e("Avisynth open failure:\n%s", s);
290 mpAvisynthClipInfo->Release();
291 mpAvisynthClipInfo = nullptr;
292 AVIFileRelease(mpAVIFile);
293 mpAVIFile = nullptr;
294 throw e;
295 }
296
297 //VDLogAppMessage(kVDLogInfo, kVDST_AVIReadHandler, kVDM_AvisynthDetected);
298 }
299 }
300
~AVIReadHandlerTunnelW32()301 AVIReadHandlerTunnelW32::~AVIReadHandlerTunnelW32() {
302 if (mpAvisynthClipInfo) {
303 mpAvisynthClipInfo->Release();
304 mpAvisynthClipInfo = nullptr;
305 }
306
307 if (mpAVIFile) {
308 AVIFileRelease(mpAVIFile);
309 mpAVIFile = nullptr;
310 }
311 }
312
AppendFile(const wchar_t * pszFile)313 bool AVIReadHandlerTunnelW32::AppendFile(const wchar_t *pszFile) {
314 return false;
315 }
316
Release()317 void AVIReadHandlerTunnelW32::Release() {
318 if (!--mRefCount)
319 delete this;
320 }
321
AddRef()322 void AVIReadHandlerTunnelW32::AddRef() {
323 ++mRefCount;
324 }
325
GetStream(uint32 fccType,int lParam)326 IAVIReadStream *AVIReadHandlerTunnelW32::GetStream(uint32 fccType, int lParam) {
327 PAVISTREAM pas;
328 HRESULT hr;
329
330 if (IsMMXState())
331 throw MyInternalError("MMX state left on: %s:%d", __FILE__, __LINE__);
332
333 hr = AVIFileGetStream(mpAVIFile, &pas, fccType, lParam);
334
335 ClearMMXState();
336
337 if (hr)
338 return nullptr;
339
340 return new AVIReadTunnelStream(this, pas, mpAvisynthClipInfo);
341 }
342
EnableFastIO(bool f)343 void AVIReadHandlerTunnelW32::EnableFastIO(bool f) {
344 }
345
isOptimizedForRealtime()346 bool AVIReadHandlerTunnelW32::isOptimizedForRealtime() {
347 return false;
348 }
349
isStreaming()350 bool AVIReadHandlerTunnelW32::isStreaming() {
351 return false;
352 }
353
isIndexFabricated()354 bool AVIReadHandlerTunnelW32::isIndexFabricated() {
355 return false;
356 }
357
getSegmentHint(const char ** ppszPath)358 bool AVIReadHandlerTunnelW32::getSegmentHint(const char **ppszPath) {
359 if (ppszPath)
360 *ppszPath = nullptr;
361
362 return false;
363 }
364
GetTextInfo(tTextInfo & textInfo)365 void AVIReadHandlerTunnelW32::GetTextInfo(tTextInfo& textInfo) {
366 textInfo.clear();
367 }
368
GetTextInfoEncoding(int & codePage,int & countryCode,int & language,int & dialect)369 void AVIReadHandlerTunnelW32::GetTextInfoEncoding(int& codePage, int& countryCode, int& language, int& dialect) {
370 codePage = 0;
371 countryCode = 0;
372 language = 0;
373 dialect = 0;
374 }
375