root/branches/perian-1.1/FFissionCodec/FFissionDecoder.cpp

Revision 923, 14.2 kB (checked in by astrange, 5 months ago)

Merge trunk to the branch.
Disable ssse3 qpel stuff (https://roundup.mplayerhq.hu/roundup/ffmpeg/issue463)

Line 
1 /*
2  *  FFissionDecoder.cpp
3  *
4  *  Copyright (c) 2006  David Conrad
5  *
6  *  This program is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU Lesser General Public
8  *  License as published by the Free Software Foundation;
9  *  version 2.1 of the License.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *  Lesser General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Lesser General Public
17  *  License along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #include "FFissionDecoder.h"
23 #include "ACCodecDispatch.h"
24 #include "FFusionCodec.h"
25 #include "Codecprintf.h"
26 #include "CodecIDs.h"
27
28 typedef struct CookieAtomHeader {
29     long           size;
30     long           type;
31     unsigned char  data[1];
32 } CookieAtomHeader;
33
34 struct CodecPair {
35         OSType mFormatID;
36         CodecID codecID;
37 };
38
39 static const CodecPair kAllInputFormats[] =
40 {
41         { kAudioFormatWMA1MS, CODEC_ID_WMAV1 },
42         { kAudioFormatWMA2MS, CODEC_ID_WMAV2 },
43         { kAudioFormatFlashADPCM, CODEC_ID_ADPCM_SWF },
44         { kAudioFormatXiphVorbis, CODEC_ID_VORBIS },
45         { kAudioFormatMPEGLayer2, CODEC_ID_MP2 },
46         { kAudioFormatMPEGLayer1, CODEC_ID_MP2 },
47         { 0x6d730050, CODEC_ID_MP2 },
48         { kAudioFormatTTA, CODEC_ID_TTA },
49         { kAudioFormatDTS, CODEC_ID_DTS },
50         { kAudioFormatNellymoser, CODEC_ID_NELLYMOSER },
51         { 0, CODEC_ID_NONE }
52 };
53
54 static CodecID GetCodecID(OSType formatID)
55 {
56         for (int i = 0; kAllInputFormats[i].codecID != CODEC_ID_NONE; i++) {
57                 if (kAllInputFormats[i].mFormatID == formatID)
58                         return kAllInputFormats[i].codecID;
59         }
60         return CODEC_ID_NONE;
61 }
62
63
64 FFissionDecoder::FFissionDecoder(UInt32 inInputBufferByteSize) : FFissionCodec(0)
65 {
66         kIntPCMOutFormatFlag = kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kLinearPCMFormatFlagIsPacked;
67         magicCookie = NULL;
68         magicCookieSize = 0;
69        
70         for (int i = 0; kAllInputFormats[i].codecID != CODEC_ID_NONE; i++) {
71                 CAStreamBasicDescription theInputFormat(kAudioStreamAnyRate, kAllInputFormats[i].mFormatID, 0, 1, 0, 0, 0, 0);
72                 AddInputFormat(theInputFormat);
73         }
74        
75         // libavcodec outputs 16-bit native-endian integer pcm, so why do conversions ourselves?
76         CAStreamBasicDescription theOutputFormat(kAudioStreamAnyRate, kAudioFormatLinearPCM, 0, 1, 0, 0, 16, kIntPCMOutFormatFlag);
77         AddOutputFormat(theOutputFormat);
78        
79         inputBuffer.Initialize(inInputBufferByteSize);
80         outBufUsed = 0;
81         outBufSize = AVCODEC_MAX_AUDIO_FRAME_SIZE;
82         outputBuffer = new Byte[outBufSize];
83 }
84
85 FFissionDecoder::~FFissionDecoder()
86 {
87         if (magicCookie)
88                 delete[] magicCookie;
89        
90         delete[] outputBuffer;
91 }
92
93 void FFissionDecoder::Initialize(const AudioStreamBasicDescription* inInputFormat, const AudioStreamBasicDescription* inOutputFormat, const void* inMagicCookie, UInt32 inMagicCookieByteSize)
94 {
95         if (inMagicCookieByteSize > 0)
96                 SetMagicCookie(inMagicCookie, inMagicCookieByteSize);
97        
98         FFissionCodec::Initialize(inInputFormat, inOutputFormat, inMagicCookie, inMagicCookieByteSize);
99 }
100
101 void FFissionDecoder::Uninitialize()
102 {
103         outBufUsed = 0;
104         inputBuffer.Zap(inputBuffer.GetDataAvailable());
105        
106         FFissionCodec::Uninitialize();
107 }
108
109 void FFissionDecoder::Reset()
110 {
111         outBufUsed = 0;
112         inputBuffer.Zap(inputBuffer.GetDataAvailable());
113        
114         FFissionCodec::Reset();
115 }
116
117 void FFissionDecoder::SetMagicCookie(const void* inMagicCookieData, UInt32 inMagicCookieDataByteSize)
118 {
119         if (magicCookie)
120                 delete[] magicCookie;
121        
122         magicCookieSize = inMagicCookieDataByteSize;
123        
124         if (magicCookieSize > 0) {
125                 magicCookie = new Byte[magicCookieSize + FF_INPUT_BUFFER_PADDING_SIZE];
126                 memcpy(magicCookie, inMagicCookieData, magicCookieSize);
127         } else
128                 magicCookie = NULL;
129        
130         FFissionCodec::SetMagicCookie(inMagicCookieData, inMagicCookieDataByteSize);
131 }
132
133 void FFissionDecoder::SetupExtradata(OSType formatID)
134 {
135         if (!magicCookie) return;
136        
137         switch (formatID) {
138                 case kAudioFormatWMA1MS:
139                 case kAudioFormatWMA2MS:
140                 case kAudioFormatTTA:
141                         if (magicCookieSize < 12 + 18 + 8 + 8)
142                                 return;
143                        
144                         avContext->extradata = magicCookie + 12 + 18 + 8;
145                         avContext->extradata_size = magicCookieSize - 12 - 18 - 8 - 8;
146                         break;
147                        
148                 case kAudioFormatXiphVorbis:
149                         avContext->extradata_size = ConvertXiphVorbisCookie();
150                         avContext->extradata = magicCookie;
151                         break;
152                        
153                 default:
154                         return;
155         }
156        
157         // this is safe because we always allocate this amount of additional memory for our copy of the magic cookie
158         memset(avContext->extradata + avContext->extradata_size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
159 }
160
161 int FFissionDecoder::ConvertXiphVorbisCookie()
162 {
163         Byte *ptr = magicCookie;
164         Byte *cend = magicCookie + magicCookieSize;
165         Byte *headerData[3] = {NULL};
166         int headerSize[3] = {0};
167        
168         while (ptr < cend) {
169                 CookieAtomHeader *aheader = reinterpret_cast<CookieAtomHeader *>(ptr);
170                 int size = EndianU32_BtoN(aheader->size);
171                 ptr += size;
172                 if (ptr > cend || size <= 0)
173                         break;
174                
175                 switch(EndianS32_BtoN(aheader->type)) {
176                         case kCookieTypeVorbisHeader:
177                                 headerData[0] = aheader->data;
178                                 headerSize[0] = size - 8;
179                                 break;
180                                
181                         case kCookieTypeVorbisComments:
182                                 headerData[1] = aheader->data;
183                                 headerSize[1] = size - 8;
184                                 break;
185                                
186                         case kCookieTypeVorbisCodebooks:
187                                 headerData[2] = aheader->data;
188                                 headerSize[2] = size - 8;
189                                 break;
190                 }
191         }
192        
193     if (headerSize[0] <= 0 || headerSize[1] <= 0 || headerSize[2] <= 0) {
194                 Codecprintf(NULL, "Invalid Vorbis extradata\n");
195                 return 0;
196         }
197        
198         int len = headerSize[0] + headerSize[1] + headerSize[2];
199         Byte *newCookie = new Byte[len + len/255 + 64];
200         ptr = newCookie;
201        
202         ptr[0] = 2;             // number of packets minus 1
203         int offset = 1;
204         offset += av_xiphlacing(&ptr[offset], headerSize[0]);
205         offset += av_xiphlacing(&ptr[offset], headerSize[1]);
206         for (int i = 0; i < 3; i++) {
207                 memcpy(&ptr[offset], headerData[i], headerSize[i]);
208                 offset += headerSize[i];
209         }
210        
211         delete[] magicCookie;
212         magicCookie = newCookie;
213         magicCookieSize = offset;
214        
215         return offset;
216 }
217
218 void FFissionDecoder::GetProperty(AudioCodecPropertyID inPropertyID, UInt32& ioPropertyDataSize, void* outPropertyData) {
219         switch (inPropertyID) {
220                 case kAudioCodecPropertyNameCFString:
221                         if (ioPropertyDataSize != sizeof(CFStringRef))
222                                 CODEC_THROW(kAudioCodecBadPropertySizeError);
223                         break;
224                        
225                 case kAudioCodecPropertyInputBufferSize:
226                 case kAudioCodecPropertyUsedInputBufferSize:
227                         if (ioPropertyDataSize != sizeof(UInt32))
228                                 CODEC_THROW(kAudioCodecBadPropertySizeError);
229                         break;
230         }
231        
232         switch (inPropertyID) {
233                 case kAudioCodecPropertyNameCFString:
234                         CFStringRef name = CFCopyLocalizedStringFromTableInBundle(CFSTR("Perian FFmpeg audio decoder"), CFSTR("CodecNames"), GetCodecBundle(), CFSTR(""));
235                         *(CFStringRef*)outPropertyData = name;
236                         break;
237                        
238                 case kAudioCodecPropertyInputBufferSize:
239                         *reinterpret_cast<UInt32*>(outPropertyData) = inputBuffer.GetBufferByteSize();
240                         break;
241                        
242                 case kAudioCodecPropertyUsedInputBufferSize:
243                         *reinterpret_cast<UInt32*>(outPropertyData) = inputBuffer.GetDataAvailable();
244                         break;
245                        
246                 default:
247                         FFissionCodec::GetProperty(inPropertyID, ioPropertyDataSize, outPropertyData);
248         }
249 }
250
251 void FFissionDecoder::SetCurrentInputFormat(const AudioStreamBasicDescription& inInputFormat)
252 {
253         if(mIsInitialized) {
254                 CODEC_THROW(kAudioCodecStateError);
255         }
256        
257         if (avCodec) {
258                 avcodec_close(avContext);
259                 avCodec = NULL;
260         }
261        
262         CodecID codecID = GetCodecID(inInputFormat.mFormatID);
263        
264         // check to make sure the input format is legal
265         if (avcodec_find_decoder(codecID) == NULL) {
266                 Codecprintf(NULL, "Unsupported input format id %4.4s\n", &inInputFormat.mFormatID);
267                 CODEC_THROW(kAudioCodecUnsupportedFormatError);
268         }
269        
270         // tell our base class about the new format
271         FFissionCodec::SetCurrentInputFormat(inInputFormat);
272 }
273        
274 void FFissionDecoder::OpenAVCodec()
275 {
276         if (!mIsInitialized)
277                 CODEC_THROW(kAudioCodecStateError);
278        
279         CodecID codecID = GetCodecID(mInputFormat.mFormatID);
280        
281         avCodec = avcodec_find_decoder(codecID);
282        
283         avcodec_get_context_defaults(avContext);
284        
285         avContext->sample_rate = mInputFormat.mSampleRate;
286         avContext->channels = mInputFormat.mChannelsPerFrame;
287         avContext->block_align = mInputFormat.mBytesPerPacket;
288         avContext->frame_size = mInputFormat.mFramesPerPacket;
289         avContext->bits_per_sample = mInputFormat.mBitsPerChannel;
290        
291         if (avContext->sample_rate == 0) {
292                 Codecprintf(NULL, "Invalid sample rate %d\n", avContext->sample_rate);
293                 avCodec = NULL;
294                 return;
295         }
296        
297         if (magicCookie) {
298                 SetupExtradata(mInputFormat.mFormatID);
299         }
300        
301         if (avcodec_open(avContext, avCodec)) {
302                 Codecprintf(NULL, "error opening audio avcodec\n");
303                 avCodec = NULL;
304                 CODEC_THROW(kAudioCodecUnsupportedFormatError);
305         }
306 }
307
308 void FFissionDecoder::SetCurrentOutputFormat(const AudioStreamBasicDescription& inOutputFormat)
309 {
310         if(mIsInitialized) {
311                 CODEC_THROW(kAudioCodecStateError);
312         }
313        
314         //      check to make sure the output format is legal
315         if (inOutputFormat.mFormatID != kAudioFormatLinearPCM ||
316                 inOutputFormat.mFormatFlags != kIntPCMOutFormatFlag ||
317                 inOutputFormat.mBitsPerChannel != 16)
318         {
319                 Codecprintf(NULL, "We only support 16 bit native endian signed integer for output\n");
320                 CODEC_THROW(kAudioCodecUnsupportedFormatError);
321         }
322        
323         //      tell our base class about the new format
324         FFissionCodec::SetCurrentOutputFormat(inOutputFormat);
325 }
326
327 void FFissionDecoder::AppendInputData(const void* inInputData, UInt32& ioInputDataByteSize,
328                                                                           UInt32& ioNumberPackets, const AudioStreamPacketDescription* inPacketDescription)
329 {
330         const Byte *inData = (const Byte *)inInputData;
331        
332         if (inPacketDescription && ioNumberPackets) {
333                 for (int i = 0; i < ioNumberPackets; i++) {
334                         UInt32 packetSize = inPacketDescription[i].mDataByteSize;
335                         inputBuffer.In(inData + inPacketDescription[i].mStartOffset, packetSize);
336                 }
337         } else if (mInputFormat.mBytesPerPacket != 0) {
338                 // no packet description, assume cbr
339                 UInt32 amountToCopy = FFMIN(mInputFormat.mBytesPerPacket * ioNumberPackets, ioInputDataByteSize);
340                 UInt32 numPackets = amountToCopy / mInputFormat.mBytesPerPacket;
341                
342                 ioInputDataByteSize = amountToCopy;
343                 ioNumberPackets = numPackets;
344                
345                 for (int i = 0; i < numPackets; i++) {
346                         UInt32 packetSize = mInputFormat.mBytesPerPacket;
347                         inputBuffer.In(inData, packetSize);
348                         inData += mInputFormat.mBytesPerPacket;
349                 }
350         } else {
351                 // XiphQT throws this in this situation (we need packet descriptions, but don't get them)
352                 // is there a better error to throw?
353                 CODEC_THROW(kAudioCodecNotEnoughBufferSpaceError);
354         }
355 }
356
357 UInt32 FFissionDecoder::ProduceOutputPackets(void* outOutputData,
358                                                                                          UInt32& ioOutputDataByteSize,  // number of bytes written to outOutputData
359                                                                                          UInt32& ioNumberPackets,
360                                                                                          AudioStreamPacketDescription* outPacketDescription)
361 {
362         UInt32 ans;
363        
364         if (!avCodec)
365                 OpenAVCodec();
366        
367         if (!mIsInitialized || !avCodec)
368                 CODEC_THROW(kAudioCodecStateError);
369        
370         UInt32 written = 0;
371         Byte *outData = (Byte *) outOutputData;
372        
373         // we have leftovers from the last packet, use that first
374         if (outBufUsed > 0) {
375                 int amountToCopy = FFMIN(outBufUsed, ioOutputDataByteSize);
376                 memcpy(outData, outputBuffer, amountToCopy);
377                 outBufUsed -= amountToCopy;
378                 written += amountToCopy;
379                
380                 if (outBufUsed > 0)
381                         memmove(outputBuffer, outputBuffer + amountToCopy, outBufUsed);
382         }
383        
384         // loop until we satisfy the request or run out of input data
385         while (written < ioOutputDataByteSize && inputBuffer.GetNumPackets() > 0) {
386                 int packetSize = inputBuffer.GetCurrentPacketSize();
387                 uint8_t *packet = inputBuffer.GetData();
388                
389                 // decode one packet to our buffer
390                 outBufUsed = outBufSize;
391                 int len = avcodec_decode_audio2(avContext, (int16_t *)outputBuffer, &outBufUsed, packet, packetSize);
392                
393                 if (len < 0) {
394                         Codecprintf(NULL, "Error decoding audio frame\n");
395                         inputBuffer.Zap(packetSize);
396                         outBufUsed = 0;
397                         ioOutputDataByteSize = written;
398                         ioNumberPackets = ioOutputDataByteSize / (2 * mOutputFormat.NumberChannels());
399                         return kAudioCodecProduceOutputPacketFailure;
400                 }
401                 inputBuffer.Zap(len);
402                
403                 // copy up to the amount requested
404                 int amountToCopy = FFMIN(outBufUsed, ioOutputDataByteSize - written);
405                 memcpy(outData + written, outputBuffer, amountToCopy);
406                 outBufUsed -= amountToCopy;
407                 written += amountToCopy;
408                
409                 // and save what's left over
410                 if (outBufUsed > 0)
411                         memmove(outputBuffer, outputBuffer + amountToCopy, outBufUsed);
412         }
413        
414         if (written < ioOutputDataByteSize)
415                 ans = kAudioCodecProduceOutputPacketNeedsMoreInputData;
416         else if (inputBuffer.GetNumPackets() > 0)
417                 // we have an entire packet left to decode
418                 ans = kAudioCodecProduceOutputPacketSuccessHasMore;
419         else
420                 ans = kAudioCodecProduceOutputPacketSuccess;
421        
422         ioOutputDataByteSize = written;
423         ioNumberPackets = ioOutputDataByteSize / (2 * mOutputFormat.NumberChannels());
424        
425         return ans;
426 }
427
428 UInt32 FFissionDecoder::GetVersion() const
429 {
430         return kFFusionCodecVersion;
431 }
432
433 // comment from XiphQT (variable frames per packet means FrameSize should be reported 0,
434 // but apparently needs 1 on Intel?):
435 /* The following line has been changed according to Apple engineers' suggestion
436    I received via Steve Nicolai (in response to *my* bugreport, I think...).
437    (Why don't they just implement the VBR-VFPP properly? *sigh*) */
438 #ifdef TARGET_CPU_X86
439 #define SHOULD_BE_ZERO 1
440 #else
441 #define SHOULD_BE_ZERO 0
442 #endif
443
444 void FFissionVBRDecoder::GetProperty(AudioCodecPropertyID inPropertyID, UInt32& ioPropertyDataSize, void* outPropertyData)
445 {
446         switch (inPropertyID) {
447                 case kAudioCodecPropertyPacketFrameSize:
448                 case kAudioCodecPropertyHasVariablePacketByteSizes:
449                 case kAudioCodecPropertyRequiresPacketDescription:
450                         if (ioPropertyDataSize != sizeof(UInt32))
451                                 CODEC_THROW(kAudioCodecBadPropertySizeError);
452                         break;
453         }
454        
455         switch (inPropertyID) {
456                 case kAudioCodecPropertyPacketFrameSize:
457                         *reinterpret_cast<UInt32*>(outPropertyData) = SHOULD_BE_ZERO;
458                         break;
459                        
460                 case kAudioCodecPropertyHasVariablePacketByteSizes:
461                 case kAudioCodecPropertyRequiresPacketDescription:
462                         *reinterpret_cast<UInt32*>(outPropertyData) = true;
463                         break;
464                        
465                 default:
466                         FFissionDecoder::GetProperty(inPropertyID, ioPropertyDataSize, outPropertyData);
467         }
468 }
469
470
471 extern "C"
472 ComponentResult FFissionDecoderEntry(ComponentParameters* inParameters, FFissionDecoder* inThis)
473 {
474         return ACCodecDispatch(inParameters, inThis);
475 }
476
477 extern "C"
478 ComponentResult FFissionVBRDecoderEntry(ComponentParameters* inParameters, FFissionVBRDecoder* inThis)
479 {
480         return ACCodecDispatch(inParameters, inThis);
481 }
Note: See TracBrowser for help on using the browser.