xref: /aosp_15_r20/external/lzma/CPP/7zip/Archive/FlvHandler.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1 // FlvHandler.cpp
2 
3 #include "StdAfx.h"
4 
5 // #include <stdio.h>
6 
7 #include "../../../C/CpuArch.h"
8 
9 #include "../../Common/ComTry.h"
10 #include "../../Common/MyBuffer.h"
11 #include "../../Common/MyString.h"
12 
13 #include "../../Windows/PropVariant.h"
14 
15 #include "../Common/InBuffer.h"
16 #include "../Common/ProgressUtils.h"
17 #include "../Common/RegisterArc.h"
18 #include "../Common/StreamObjects.h"
19 #include "../Common/StreamUtils.h"
20 
21 #define GetBe24(p) ( \
22     ((UInt32)((const Byte *)(p))[0] << 16) | \
23     ((UInt32)((const Byte *)(p))[1] <<  8) | \
24              ((const Byte *)(p))[2] )
25 
26 // #define Get16(p) GetBe16(p)
27 #define Get24(p) GetBe24(p)
28 #define Get32(p) GetBe32(p)
29 
30 namespace NArchive {
31 namespace NFlv {
32 
33 // static const UInt32 kFileSizeMax = (UInt32)1 << 30;
34 static const UInt32 kNumChunksMax = (UInt32)1 << 23;
35 
36 static const UInt32 kTagHeaderSize = 11;
37 
38 static const Byte kFlag_Video = 1;
39 static const Byte kFlag_Audio = 4;
40 
41 static const Byte kType_Audio = 8;
42 static const Byte kType_Video = 9;
43 static const Byte kType_Meta = 18;
44 static const unsigned kNumTypes = 19;
45 
46 struct CItem
47 {
48   CByteBuffer Data;
49   Byte Type;
50 };
51 
52 struct CItem2
53 {
54   Byte Type;
55   Byte SubType;
56   Byte Props;
57   bool SameSubTypes;
58   unsigned NumChunks;
59   size_t Size;
60 
61   CReferenceBuf *BufSpec;
62   CMyComPtr<IUnknown> RefBuf;
63 
IsAudioNArchive::NFlv::CItem264   bool IsAudio() const { return Type == kType_Audio; }
65 };
66 
67 
68 Z7_CLASS_IMP_CHandler_IInArchive_1(
69   IInArchiveGetStream
70 )
71   CMyComPtr<IInStream> _stream;
72   CObjectVector<CItem2> _items2;
73   CByteBuffer _metadata;
74   bool _isRaw;
75   UInt64 _phySize;
76 
77   HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback);
78   // AString GetComment();
79 };
80 
81 static const Byte kProps[] =
82 {
83   kpidSize,
84   kpidNumBlocks,
85   kpidComment
86 };
87 
88 IMP_IInArchive_Props
89 IMP_IInArchive_ArcProps_NO_Table
90 
91 static const char * const g_AudioTypes[16] =
92 {
93     "pcm"
94   , "adpcm"
95   , "mp3"
96   , "pcm_le"
97   , "nellymoser16"
98   , "nellymoser8"
99   , "nellymoser"
100   , "g711a"
101   , "g711m"
102   , "audio9"
103   , "aac"
104   , "speex"
105   , "audio12"
106   , "audio13"
107   , "mp3"
108   , "audio15"
109 };
110 
111 static const char * const g_VideoTypes[16] =
112 {
113     "video0"
114   , "jpeg"
115   , "h263"
116   , "screen"
117   , "vp6"
118   , "vp6alpha"
119   , "screen2"
120   , "avc"
121   , "video8"
122   , "video9"
123   , "video10"
124   , "video11"
125   , "video12"
126   , "video13"
127   , "video14"
128   , "video15"
129 };
130 
131 static const char * const g_Rates[4] =
132 {
133     "5.5 kHz"
134   , "11 kHz"
135   , "22 kHz"
136   , "44 kHz"
137 };
138 
Z7_COM7F_IMF(CHandler::GetProperty (UInt32 index,PROPID propID,PROPVARIANT * value))139 Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
140 {
141   NWindows::NCOM::CPropVariant prop;
142   const CItem2 &item = _items2[index];
143   switch (propID)
144   {
145     case kpidExtension:
146       prop = _isRaw ?
147         (item.IsAudio() ? g_AudioTypes[item.SubType] : g_VideoTypes[item.SubType]) :
148         (item.IsAudio() ? "audio.flv" : "video.flv");
149       break;
150     case kpidSize:
151     case kpidPackSize:
152       prop = (UInt64)item.Size;
153       break;
154     case kpidNumBlocks: prop = (UInt32)item.NumChunks; break;
155     case kpidComment:
156     {
157       char sz[64];
158       char *s = MyStpCpy(sz, (item.IsAudio() ? g_AudioTypes[item.SubType] : g_VideoTypes[item.SubType]) );
159       if (item.IsAudio())
160       {
161         *s++ = ' ';
162         s = MyStpCpy(s, g_Rates[(item.Props >> 2) & 3]);
163         s = MyStpCpy(s, (item.Props & 2) ? " 16-bit" : " 8-bit");
164         s = MyStpCpy(s, (item.Props & 1) ? " stereo" : " mono");
165       }
166       prop = sz;
167       break;
168     }
169   }
170   prop.Detach(value);
171   return S_OK;
172 }
173 
174 /*
175 AString CHandler::GetComment()
176 {
177   const Byte *p = _metadata;
178   size_t size = _metadata.Size();
179   AString res;
180   if (size > 0)
181   {
182     p++;
183     size--;
184     for (;;)
185     {
186       if (size < 2)
187         break;
188       int len = Get16(p);
189       p += 2;
190       size -= 2;
191       if (len == 0 || (size_t)len > size)
192         break;
193       {
194         AString temp;
195         temp.SetFrom_CalcLen((const char *)p, len);
196         if (!res.IsEmpty())
197           res += '\n';
198         res += temp;
199       }
200       p += len;
201       size -= len;
202       if (size < 1)
203         break;
204       Byte type = *p++;
205       size--;
206       bool ok = false;
207       switch (type)
208       {
209         case 0:
210         {
211           if (size < 8)
212             break;
213           ok = true;
214           Byte reverse[8];
215           for (int i = 0; i < 8; i++)
216           {
217             bool little_endian = 1;
218             if (little_endian)
219               reverse[i] = p[7 - i];
220             else
221               reverse[i] = p[i];
222           }
223           double d = *(double *)reverse;
224           char temp[32];
225           sprintf(temp, " = %.3f", d);
226           res += temp;
227           p += 8;
228           size -= 8;
229           break;
230         }
231         case 8:
232         {
233           if (size < 4)
234             break;
235           ok = true;
236           // UInt32 numItems = Get32(p);
237           p += 4;
238           size -= 4;
239           break;
240         }
241       }
242       if (!ok)
243         break;
244     }
245   }
246   return res;
247 }
248 */
249 
Z7_COM7F_IMF(CHandler::GetArchiveProperty (PROPID propID,PROPVARIANT * value))250 Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
251 {
252   // COM_TRY_BEGIN
253   NWindows::NCOM::CPropVariant prop;
254   switch (propID)
255   {
256     // case kpidComment: prop = GetComment(); break;
257     case kpidPhySize: prop = (UInt64)_phySize; break;
258     case kpidIsNotArcType: prop = true; break;
259   }
260   prop.Detach(value);
261   return S_OK;
262   // COM_TRY_END
263 }
264 
Open2(IInStream * stream,IArchiveOpenCallback * callback)265 HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
266 {
267   const UInt32 kHeaderSize = 13;
268   Byte header[kHeaderSize];
269   RINOK(ReadStream_FALSE(stream, header, kHeaderSize))
270   if (header[0] != 'F' ||
271       header[1] != 'L' ||
272       header[2] != 'V' ||
273       header[3] != 1 ||
274       (header[4] & 0xFA) != 0)
275     return S_FALSE;
276   UInt64 offset = Get32(header + 5);
277   if (offset != 9 || Get32(header + 9) != 0)
278     return S_FALSE;
279   offset = kHeaderSize;
280 
281   CInBuffer inBuf;
282   if (!inBuf.Create(1 << 15))
283     return E_OUTOFMEMORY;
284   inBuf.SetStream(stream);
285 
286   CObjectVector<CItem> items;
287   int lasts[kNumTypes];
288   unsigned i;
289   for (i = 0; i < kNumTypes; i++)
290     lasts[i] = -1;
291 
292   _phySize = offset;
293   for (;;)
294   {
295     Byte buf[kTagHeaderSize];
296     CItem item;
297     if (inBuf.ReadBytes(buf, kTagHeaderSize) != kTagHeaderSize)
298       break;
299     item.Type = buf[0];
300     UInt32 size = Get24(buf + 1);
301     if (size < 1)
302       break;
303     // item.Time = Get24(buf + 4);
304     // item.Time |= (UInt32)buf[7] << 24;
305     if (Get24(buf + 8) != 0) // streamID
306       break;
307 
308     UInt32 curSize = kTagHeaderSize + size + 4;
309     item.Data.Alloc(curSize);
310     memcpy(item.Data, buf, kTagHeaderSize);
311     if (inBuf.ReadBytes(item.Data + kTagHeaderSize, size) != size)
312       break;
313     if (inBuf.ReadBytes(item.Data + kTagHeaderSize + size, 4) != 4)
314       break;
315 
316     if (Get32(item.Data + kTagHeaderSize + size) != kTagHeaderSize + size)
317       break;
318 
319     offset += curSize;
320 
321     // printf("\noffset = %6X type = %2d time = %6d size = %6d", (UInt32)offset, item.Type, item.Time, item.Size);
322 
323     if (item.Type == kType_Meta)
324     {
325       // _metadata = item.Buf;
326     }
327     else
328     {
329       if (item.Type != kType_Audio && item.Type != kType_Video)
330         break;
331       if (items.Size() >= kNumChunksMax)
332         return S_FALSE;
333       Byte firstByte = item.Data[kTagHeaderSize];
334       Byte subType, props;
335       if (item.Type == kType_Audio)
336       {
337         subType = (Byte)(firstByte >> 4);
338         props = (Byte)(firstByte & 0xF);
339       }
340       else
341       {
342         subType = (Byte)(firstByte & 0xF);
343         props = (Byte)(firstByte >> 4);
344       }
345       int last = lasts[item.Type];
346       if (last < 0)
347       {
348         CItem2 item2;
349         item2.RefBuf = item2.BufSpec = new CReferenceBuf;
350         item2.Size = curSize;
351         item2.Type = item.Type;
352         item2.SubType = subType;
353         item2.Props = props;
354         item2.NumChunks = 1;
355         item2.SameSubTypes = true;
356         lasts[item.Type] = (int)_items2.Add(item2);
357       }
358       else
359       {
360         CItem2 &item2 = _items2[last];
361         if (subType != item2.SubType)
362           item2.SameSubTypes = false;
363         item2.Size += curSize;
364         item2.NumChunks++;
365       }
366       items.Add(item);
367     }
368     _phySize = offset;
369     if (callback && (items.Size() & 0xFF) == 0)
370     {
371       RINOK(callback->SetCompleted(NULL, &offset))
372     }
373   }
374   if (items.IsEmpty())
375     return S_FALSE;
376 
377   _isRaw = (_items2.Size() == 1);
378   for (i = 0; i < _items2.Size(); i++)
379   {
380     CItem2 &item2 = _items2[i];
381     CByteBuffer &itemBuf = item2.BufSpec->Buf;
382     if (_isRaw)
383     {
384       if (!item2.SameSubTypes)
385         return S_FALSE;
386       itemBuf.Alloc((size_t)item2.Size - (size_t)(kTagHeaderSize + 4 + 1) * item2.NumChunks);
387       item2.Size = 0;
388     }
389     else
390     {
391       itemBuf.Alloc(kHeaderSize + (size_t)item2.Size);
392       memcpy(itemBuf, header, kHeaderSize);
393       itemBuf[4] = item2.IsAudio() ? kFlag_Audio : kFlag_Video;
394       item2.Size = kHeaderSize;
395     }
396   }
397 
398   for (i = 0; i < items.Size(); i++)
399   {
400     const CItem &item = items[i];
401     CItem2 &item2 = _items2[lasts[item.Type]];
402     size_t size = item.Data.Size();
403     const Byte *src = item.Data;
404     if (_isRaw)
405     {
406       src += kTagHeaderSize + 1;
407       size -= (kTagHeaderSize + 4 + 1);
408     }
409     if (size != 0)
410     {
411       memcpy(item2.BufSpec->Buf + item2.Size, src, size);
412       item2.Size += size;
413     }
414   }
415   return S_OK;
416 }
417 
Z7_COM7F_IMF(CHandler::Open (IInStream * inStream,const UInt64 *,IArchiveOpenCallback * callback))418 Z7_COM7F_IMF(CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *callback))
419 {
420   COM_TRY_BEGIN
421   Close();
422   HRESULT res;
423   try
424   {
425     res = Open2(inStream, callback);
426     if (res == S_OK)
427       _stream = inStream;
428   }
429   catch(...) { res = S_FALSE; }
430   if (res != S_OK)
431   {
432     Close();
433     return S_FALSE;
434   }
435   return S_OK;
436   COM_TRY_END
437 }
438 
Z7_COM7F_IMF(CHandler::Close ())439 Z7_COM7F_IMF(CHandler::Close())
440 {
441   _phySize = 0;
442   _stream.Release();
443   _items2.Clear();
444   // _metadata.SetCapacity(0);
445   return S_OK;
446 }
447 
Z7_COM7F_IMF(CHandler::GetNumberOfItems (UInt32 * numItems))448 Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
449 {
450   *numItems = _items2.Size();
451   return S_OK;
452 }
453 
Z7_COM7F_IMF(CHandler::Extract (const UInt32 * indices,UInt32 numItems,Int32 testMode,IArchiveExtractCallback * extractCallback))454 Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
455     Int32 testMode, IArchiveExtractCallback *extractCallback))
456 {
457   COM_TRY_BEGIN
458   const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
459   if (allFilesMode)
460     numItems = _items2.Size();
461   if (numItems == 0)
462     return S_OK;
463   UInt64 totalSize = 0;
464   UInt32 i;
465   for (i = 0; i < numItems; i++)
466     totalSize += _items2[allFilesMode ? i : indices[i]].Size;
467   extractCallback->SetTotal(totalSize);
468 
469   totalSize = 0;
470 
471   CLocalProgress *lps = new CLocalProgress;
472   CMyComPtr<ICompressProgressInfo> progress = lps;
473   lps->Init(extractCallback, false);
474 
475   for (i = 0; i < numItems; i++)
476   {
477     lps->InSize = lps->OutSize = totalSize;
478     RINOK(lps->SetCur())
479     CMyComPtr<ISequentialOutStream> outStream;
480     const Int32 askMode = testMode ?
481         NExtract::NAskMode::kTest :
482         NExtract::NAskMode::kExtract;
483     const UInt32 index = allFilesMode ? i : indices[i];
484     const CItem2 &item = _items2[index];
485     RINOK(extractCallback->GetStream(index, &outStream, askMode))
486     totalSize += item.Size;
487     if (!testMode && !outStream)
488       continue;
489     RINOK(extractCallback->PrepareOperation(askMode))
490     if (outStream)
491     {
492       RINOK(WriteStream(outStream, item.BufSpec->Buf, item.BufSpec->Buf.Size()))
493     }
494     RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
495   }
496   return S_OK;
497   COM_TRY_END
498 }
499 
Z7_COM7F_IMF(CHandler::GetStream (UInt32 index,ISequentialInStream ** stream))500 Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream))
501 {
502   COM_TRY_BEGIN
503   *stream = NULL;
504   CBufInStream *streamSpec = new CBufInStream;
505   CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
506   streamSpec->Init(_items2[index].BufSpec);
507   *stream = streamTemp.Detach();
508   return S_OK;
509   COM_TRY_END
510 }
511 
512 static const Byte k_Signature[] = { 'F', 'L', 'V', 1, };
513 
514 REGISTER_ARC_I(
515   "FLV", "flv", NULL, 0xD6,
516   k_Signature,
517   0,
518   0,
519   NULL)
520 
521 }}
522