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