/* * 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; }