| /* |
| * GStreamer QuickTime codec mapping |
| * Copyright <2006, 2007> Fluendo <gstreamer@fluendo.com> |
| * Copyright <2006, 2007> Pioneers of the Inevitable <songbird@songbirdnest.com> |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the "Software"), |
| * to deal in the Software without restriction, including without limitation |
| * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| * and/or sell copies of the Software, and to permit persons to whom the |
| * Software is furnished to do so, subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice shall be included in |
| * all copies or substantial portions of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
| * DEALINGS IN THE SOFTWARE. |
| * |
| * Alternatively, the contents of this file may be used under the |
| * GNU Lesser General Public License Version 2.1 (the "LGPL"), in |
| * which case the following provisions apply instead of the ones |
| * mentioned above: |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Library General Public |
| * License as published by the Free Software Foundation; either |
| * version 2 of the License, or (at your option) any later version. |
| * |
| * This library 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 |
| * Library General Public License for more details. |
| * |
| * You should have received a copy of the GNU Library General Public |
| * License along with this library; if not, write to the |
| * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, |
| * Boston, MA 02110-1301, USA. |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| #include "config.h" |
| #endif |
| |
| #include <string.h> |
| #include <glib.h> |
| |
| #include "qtutils.h" |
| |
| gboolean |
| get_name_info_from_component (Component componentID, |
| ComponentDescription * desc, gchar ** name, gchar ** info) |
| { |
| Handle nameHandle = NewHandle (200); |
| Handle infoHandle = NewHandle (200); |
| gchar *tmpname; |
| gchar *tmpinfo; |
| OSErr result; |
| gboolean ret = TRUE; |
| |
| result = GetComponentInfo (componentID, desc, nameHandle, infoHandle, NULL); |
| if (result != noErr) { |
| ret = FALSE; |
| goto done; |
| } |
| #if DEBUG_DUMP |
| GST_LOG ("ComponentDescription dump"); |
| gst_util_dump_mem ((const guchar *) desc, sizeof (ComponentDescription)); |
| gst_util_dump_mem ((gpointer) * nameHandle, 200); |
| gst_util_dump_mem ((gpointer) * infoHandle, 200); |
| GST_LOG ("0x%x 0x%x", **((guint8 **) nameHandle), **((guint8 **) infoHandle)); |
| #endif |
| |
| if (*nameHandle && name) { |
| gsize read, written; |
| |
| tmpname = g_strndup ((*(char **) nameHandle) + 1, |
| **((guint8 **) nameHandle)); |
| *name = g_convert_with_fallback (tmpname, -1, "ASCII", "MAC", |
| (gchar *) " ", &read, &written, NULL); |
| if (!*name) |
| GST_WARNING ("read:%" G_GSIZE_FORMAT ", written:%" G_GSIZE_FORMAT, read, |
| written); |
| g_free (tmpname); |
| } |
| |
| if (*infoHandle && info) { |
| tmpinfo = |
| g_strndup ((*(char **) infoHandle) + 1, **((guint8 **) infoHandle)); |
| *info = |
| g_convert_with_fallback (tmpinfo, -1, "ASCII", "MAC", (gchar *) " ", |
| NULL, NULL, NULL); |
| g_free (tmpinfo); |
| } |
| |
| done: |
| DisposeHandle (nameHandle); |
| DisposeHandle (infoHandle); |
| |
| return ret; |
| } |
| |
| /* |
| struct CodecDecompressParams { |
| ImageSequence sequenceID; |
| ImageDescriptionHandle imageDescription; |
| Ptr data; |
| long bufferSize; |
| long frameNumber; |
| long startLine; |
| long stopLine; |
| long conditionFlags; |
| CodecFlags callerFlags; |
| CodecCapabilities * capabilities; |
| ICMProgressProcRecord progressProcRecord; |
| ICMCompletionProcRecord completionProcRecord; |
| ICMDataProcRecord dataProcRecord; |
| CGrafPtr port; |
| PixMap dstPixMap; |
| BitMapPtr maskBits; |
| PixMapPtr mattePixMap; |
| Rect srcRect; |
| MatrixRecord * matrix; |
| CodecQ accuracy; |
| short transferMode; |
| ICMFrameTimePtr frameTime; |
| long reserved[1]; |
| SInt8 matrixFlags; |
| SInt8 matrixType; |
| Rect dstRect; |
| UInt16 majorSourceChangeSeed; |
| UInt16 minorSourceChangeSeed; |
| CDSequenceDataSourcePtr sourceData; |
| RgnHandle maskRegion; |
| OSType ** wantedDestinationPixelTypes; |
| long screenFloodMethod; |
| long screenFloodValue; |
| short preferredOffscreenPixelSize; |
| ICMFrameTimeInfoPtr syncFrameTime; |
| Boolean needUpdateOnTimeChange; |
| Boolean enableBlackLining; |
| Boolean needUpdateOnSourceChange; |
| Boolean pad; |
| long unused; |
| CGrafPtr finalDestinationPort; |
| long requestedBufferWidth; |
| long requestedBufferHeight; |
| Rect displayableAreaOfRequestedBuffer; |
| Boolean requestedSingleField; |
| Boolean needUpdateOnNextIdle; |
| Boolean pad2[2]; |
| fixed bufferGammaLevel; |
| UInt32 taskWeight; |
| OSType taskName; |
| }; |
| */ |
| |
| /* struct ImageDescription { */ |
| /* long idSize; /\* total size of this structure *\/ */ |
| /* 4 CodecType cType; /\* compressor creator type *\/ */ |
| /* 8 long resvd1; /\* reserved--must be set to 0 *\/ */ |
| /* 12 short resvd2; /\* reserved--must be set to 0 *\/ */ |
| /* 14 short dataRefIndex; /\* reserved--must be set to 0 *\/ */ |
| /* 16 short version; /\* version of compressed data *\/ */ |
| /* 18 short revisionLevel; /\* compressor that created data *\/ */ |
| /* 20 long vendor; /\* compressor developer that created data *\/ */ |
| /* 24 CodecQ temporalQuality; */ |
| /* /\* degree of temporal compression *\/ */ |
| /* 28 CodecQ spatialQuality; */ |
| /* /\* degree of spatial compression *\/ */ |
| /* 32 short width; /\* width of source image in pixels *\/ */ |
| /* 34 short height; /\* height of source image in pixels *\/ */ |
| /* 36 Fixed hRes; /\* horizontal resolution of source image *\/ */ |
| /* 40 Fixed vRes; /\* vertical resolution of source image *\/ */ |
| /* 44 long dataSize; /\* size in bytes of compressed data *\/ */ |
| /* 48 short frameCount; /\* number of frames in image data *\/ */ |
| /* 50 Str31 name; /\* name of compression algorithm *\/ */ |
| /* 82 short depth; /\* pixel depth of source image *\/ */ |
| /* 84 short clutID; /\* ID number of the color table for image *\/ */ |
| /* }; */ |
| |
| |
| gboolean |
| get_output_info_from_component (Component componentID) |
| { |
| gboolean ret = FALSE; |
| ComponentInstance instance; |
| ImageSubCodecDecompressCapabilities caps; |
| CodecInfo info; |
| |
| GST_LOG ("Creating an instance"); |
| |
| /* 1. Create an instance */ |
| if (!(instance = OpenComponent (componentID))) { |
| GST_WARNING ("Couldn't open component"); |
| return FALSE; |
| } |
| |
| /* 2. initialize */ |
| memset (&caps, 0, sizeof (ImageSubCodecDecompressCapabilities)); |
| if (ImageCodecInitialize (instance, &caps) != noErr) { |
| GST_WARNING ("ImageCodecInitialize() failed"); |
| goto beach; |
| } |
| #if DEBUG_DUMP |
| GST_LOG ("ImageSubCodecDecompressCapabilities"); |
| gst_util_dump_mem ((const guchar *) &caps, |
| sizeof (ImageSubCodecDecompressCapabilities)); |
| #endif |
| |
| GST_LOG ("recordSize:%ld", caps.recordSize); |
| GST_LOG ("decompressRecordSize:%ld", caps.decompressRecordSize); |
| GST_LOG ("canAsync:%d", caps.canAsync); |
| |
| /* 3. Get codec info */ |
| memset (&info, 0, sizeof (CodecInfo)); |
| if (ImageCodecGetCodecInfo (instance, &info) != noErr) { |
| GST_WARNING ("ImageCodecInfo() failed"); |
| goto beach; |
| }; |
| |
| #if DEBUG_DUMP |
| GST_LOG ("CodecInfo"); |
| gst_util_dump_mem ((const guchar *) &info, sizeof (CodecInfo)); |
| #endif |
| |
| GST_LOG ("version:%d", info.version); |
| GST_LOG ("revisionLevel:%d", info.revisionLevel); |
| GST_LOG ("vendor:%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (info.vendor)); |
| |
| /* Compression flags */ |
| /* Contains flags (see below) that specify the decompression capabilities of |
| * the component. Typically, these flags are of interest only to developers of |
| * image decompressors. */ |
| GST_LOG ("decompressFlags:%lx", info.decompressFlags); |
| if (info.decompressFlags & codecInfoDoes1) |
| GST_LOG ("Depth 1 OK"); |
| if (info.decompressFlags & codecInfoDoes2) |
| GST_LOG ("Depth 2 OK"); |
| if (info.decompressFlags & codecInfoDoes4) |
| GST_LOG ("Depth 4 OK"); |
| if (info.decompressFlags & codecInfoDoes8) |
| GST_LOG ("Depth 8 OK"); |
| if (info.decompressFlags & codecInfoDoes16) |
| GST_LOG ("Depth 16 OK"); |
| if (info.decompressFlags & codecInfoDoes32) |
| GST_LOG ("Depth 32 OK"); |
| GST_LOG ("compressFlags:%lx", info.compressFlags); |
| |
| /* Format FLAGS */ |
| /* Contains flags (see below) that describe the possible format for compressed |
| * data produced by this component and the format of compressed files that the |
| * component can handle during decompression. Typically, these flags are of |
| * interest only to developers of compressor components. |
| */ |
| GST_LOG ("formatFlags:%lx", info.formatFlags); |
| if (info.formatFlags & codecInfoDepth1) |
| GST_LOG ("Depth 1 OK"); |
| if (info.formatFlags & codecInfoDepth2) |
| GST_LOG ("Depth 2 OK"); |
| if (info.formatFlags & codecInfoDepth4) |
| GST_LOG ("Depth 4 OK"); |
| if (info.formatFlags & codecInfoDepth8) |
| GST_LOG ("Depth 8 OK"); |
| if (info.formatFlags & codecInfoDepth16) |
| GST_LOG ("Depth 16 OK"); |
| if (info.formatFlags & codecInfoDepth24) |
| GST_LOG ("Depth 24 OK"); |
| if (info.formatFlags & codecInfoDepth32) |
| GST_LOG ("Depth 32 OK"); |
| if (info.formatFlags & codecInfoDepth33) |
| GST_LOG ("Depth 33 OK"); |
| if (info.formatFlags & codecInfoDepth34) |
| GST_LOG ("Depth 34 OK"); |
| if (info.formatFlags & codecInfoDepth36) |
| GST_LOG ("Depth 36 OK"); |
| if (info.formatFlags & codecInfoDepth40) |
| GST_LOG ("Depth 40 OK"); |
| if (info.formatFlags & codecInfoStoresClut) |
| GST_LOG ("StoresClut OK"); |
| if (info.formatFlags & codecInfoDoesLossless) |
| GST_LOG ("Lossless OK"); |
| if (info.formatFlags & codecInfoSequenceSensitive) |
| GST_LOG ("SequenceSentitive OK"); |
| |
| |
| GST_LOG ("compressionAccuracy:%u", info.compressionAccuracy); |
| GST_LOG ("decompressionAccuracy:%u", info.decompressionAccuracy); |
| GST_LOG ("compressionSpeed:%d", info.compressionSpeed); |
| GST_LOG ("decompressionSpeed:%d", info.decompressionSpeed); |
| GST_LOG ("compressionLevel:%u", info.compressionLevel); |
| GST_LOG ("minimumHeight:%d", info.minimumHeight); |
| GST_LOG ("minimumWidth:%d", info.minimumWidth); |
| |
| /* /\* . Call ImageCodecPreDecompress *\/ */ |
| /* memset(¶ms, 0, sizeof(CodecDecompressParams)); */ |
| /* GST_LOG ("calling imagecodecpredecompress"); */ |
| /* if (ImageCodecPreDecompress (instance, ¶ms) != noErr) { */ |
| /* GST_WARNING ("Error in ImageCodecPreDecompress"); */ |
| /* goto beach; */ |
| /* } */ |
| |
| /* GST_INFO ("sequenceID : %d", params.sequenceID); */ |
| |
| ret = TRUE; |
| |
| beach: |
| /* Free instance */ |
| CloseComponent (instance); |
| return TRUE; |
| } |
| |
| void |
| dump_avcc_atom (guint8 * atom) |
| { |
| /* first 8 bytes : length + atom */ |
| GST_LOG ("version:0x%x", QT_UINT8 (atom + 8)); |
| GST_LOG ("Profile:%d", QT_UINT8 (atom + 9)); |
| GST_LOG ("Compatible profiles : 0x%x", QT_UINT8 (atom + 10)); |
| GST_LOG ("Level:%d", QT_UINT8 (atom + 11)); |
| } |
| |
| void |
| dump_image_description (ImageDescription * desc) |
| { |
| GST_LOG ("Description %p , size:%" G_GSIZE_FORMAT, desc, desc->idSize); |
| |
| #if DEBUG_DUMP |
| gst_util_dump_mem ((const guchar *) desc, desc->idSize); |
| #endif |
| |
| GST_LOG ("cType : %" GST_FOURCC_FORMAT, QT_FOURCC_ARGS (desc->cType)); |
| GST_LOG ("version:%d", desc->version); |
| GST_LOG ("revisionLevel:%d", desc->revisionLevel); |
| GST_LOG ("vendor:%" GST_FOURCC_FORMAT, QT_FOURCC_ARGS (desc->vendor)); |
| GST_LOG ("temporalQuality:%lu", desc->temporalQuality); |
| GST_LOG ("spatialQuality:%lu", desc->spatialQuality); |
| GST_LOG ("width:%u", desc->width); |
| GST_LOG ("height:%u", desc->height); |
| GST_LOG ("hres:%f", desc->hRes / 65536.0); |
| GST_LOG ("vres:%f", desc->vRes / 65536.0); |
| GST_LOG ("dataSize:%" G_GSIZE_FORMAT, desc->dataSize); |
| GST_LOG ("frameCount:%d", desc->frameCount); |
| GST_LOG ("name:%.*s", desc->name[0], desc->name + 1); |
| GST_LOG ("depth:%d", desc->depth); |
| GST_LOG ("clutID:%d", desc->clutID); |
| |
| if (desc->idSize > sizeof (ImageDescription)) { |
| guint8 *extradata = (guint8 *) desc + sizeof (ImageDescription); |
| guint32 type = QT_READ_UINT32 (extradata + 4); |
| |
| GST_LOG ("Extra Data size:%lu", |
| (gulong) desc->idSize - (gulong) sizeof (ImageDescription)); |
| #if DEBUG_DUMP |
| gst_util_dump_mem ((gpointer) (gulong) desc + |
| (gulong) sizeof (ImageDescription), |
| (gulong) desc->idSize - (gulong) sizeof (ImageDescription)); |
| #endif |
| GST_LOG ("Extra Data Type : %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (type)); |
| if (type == QT_MAKE_FOURCC ('a', 'v', 'c', 'C')) |
| dump_avcc_atom (extradata); |
| } |
| } |
| |
| void |
| dump_codec_decompress_params (CodecDecompressParams * params) |
| { |
| GST_LOG ("params %p", params); |
| |
| #if DEBUG_DUMP |
| gst_util_dump_mem ((const guchar *) params, sizeof (CodecDecompressParams)); |
| #endif |
| |
| GST_LOG ("SequenceID:%ld", params->sequenceID); |
| GST_LOG ("imageDescription:%p", params->imageDescription); |
| GST_LOG ("data:%p", params->data); |
| GST_LOG ("bufferSize:%ld", params->bufferSize); |
| GST_LOG ("frameNumber:%ld", params->frameNumber); |
| GST_LOG ("startLine:%ld , StopLine:%ld", params->startLine, |
| params->stopLine); |
| GST_LOG ("conditionFlags:0x%lx", params->conditionFlags); |
| GST_LOG ("callerFlags:0x%x", params->callerFlags); |
| GST_LOG ("capabilities:%p", params->capabilities); |
| GST_LOG ("port:%p", params->port); |
| GST_LOG ("dstPixMap"); |
| #if DEBUG_DUMP |
| gst_util_dump_mem ((const guchar *) ¶ms->dstPixMap, sizeof (PixMap)); |
| #endif |
| |
| GST_LOG ("maskBits:%p", params->maskBits); |
| GST_LOG ("mattePixMap:%p", params->mattePixMap); |
| GST_LOG ("srcRect %d/%d/%d/%d", |
| params->srcRect.top, params->srcRect.bottom, |
| params->srcRect.left, params->srcRect.right); |
| |
| GST_LOG ("matrix:%p", params->matrix); |
| GST_LOG ("accuracy:%ld", params->accuracy); |
| GST_LOG ("transferMode:%d", params->transferMode); |
| GST_LOG ("frameTime:%p", params->frameTime); |
| GST_LOG ("matrixFlags:%x", params->matrixFlags); |
| |
| GST_LOG ("dstRect %d/%d/%d/%d", |
| params->dstRect.top, params->dstRect.bottom, |
| params->dstRect.left, params->dstRect.right); |
| |
| GST_LOG ("sourceData:%p", params->sourceData); |
| |
| if (params->wantedDestinationPixelTypes) { |
| OSType *tmp; |
| |
| for (tmp = *params->wantedDestinationPixelTypes; *tmp; tmp++) |
| GST_LOG ("Destination pixel %" GST_FOURCC_FORMAT, QT_FOURCC_ARGS (*tmp)); |
| } |
| } |
| |
| void |
| addSInt32ToDictionary (CFMutableDictionaryRef dictionary, CFStringRef key, |
| SInt32 numberSInt32) |
| { |
| CFNumberRef number = |
| CFNumberCreate (NULL, kCFNumberSInt32Type, &numberSInt32); |
| if (!number) |
| return; |
| CFDictionaryAddValue (dictionary, key, number); |
| CFRelease (number); |
| } |
| |
| void |
| dump_cvpixel_buffer (CVPixelBufferRef pixbuf) |
| { |
| gsize left, right, top, bottom; |
| |
| GST_LOG ("buffer %p", pixbuf); |
| if (CVPixelBufferLockBaseAddress (pixbuf, 0)) { |
| GST_WARNING ("Couldn't lock base adress on pixel buffer !"); |
| return; |
| } |
| GST_LOG ("Width:%" G_GSIZE_FORMAT " , Height:%" G_GSIZE_FORMAT, |
| CVPixelBufferGetWidth (pixbuf), CVPixelBufferGetHeight (pixbuf)); |
| GST_LOG ("Format:%" GST_FOURCC_FORMAT, |
| GST_FOURCC_ARGS (CVPixelBufferGetPixelFormatType (pixbuf))); |
| GST_LOG ("base address:%p", CVPixelBufferGetBaseAddress (pixbuf)); |
| GST_LOG ("Bytes per row:%" G_GSIZE_FORMAT, |
| CVPixelBufferGetBytesPerRow (pixbuf)); |
| GST_LOG ("Data Size:%" G_GSIZE_FORMAT, CVPixelBufferGetDataSize (pixbuf)); |
| GST_LOG ("Plane count:%" G_GSIZE_FORMAT, CVPixelBufferGetPlaneCount (pixbuf)); |
| CVPixelBufferGetExtendedPixels (pixbuf, &left, &right, &top, &bottom); |
| GST_LOG ("Extended pixels. left/right/top/bottom : %" G_GSIZE_FORMAT |
| "/%" G_GSIZE_FORMAT "/%" G_GSIZE_FORMAT "/%" G_GSIZE_FORMAT, |
| left, right, top, bottom); |
| CVPixelBufferUnlockBaseAddress (pixbuf, 0); |
| } |
| |
| |
| // Convenience function to dispose of our audio buffers |
| void |
| DestroyAudioBufferList (AudioBufferList * list) |
| { |
| UInt32 i; |
| |
| if (list) { |
| for (i = 0; i < list->mNumberBuffers; i++) { |
| if (list->mBuffers[i].mData) |
| free (list->mBuffers[i].mData); |
| } |
| free (list); |
| } |
| } |
| |
| // Convenience function to allocate our audio buffers |
| AudioBufferList * |
| AllocateAudioBufferList (UInt32 numChannels, UInt32 size) |
| { |
| AudioBufferList *list; |
| |
| list = (AudioBufferList *) calloc (1, sizeof (AudioBufferList)); |
| if (list == NULL) |
| return NULL; |
| |
| list->mNumberBuffers = 1; |
| list->mBuffers[0].mNumberChannels = numChannels; |
| list->mBuffers[0].mDataByteSize = size; |
| list->mBuffers[0].mData = malloc (size); |
| if (list->mBuffers[0].mData == NULL) { |
| DestroyAudioBufferList (list); |
| return NULL; |
| } |
| return list; |
| } |