summaryrefslogtreecommitdiff
path: root/src/libw32dll/qt_decoder.c
diff options
context:
space:
mode:
authorGuenter Bartsch <guenter@users.sourceforge.net>2002-12-18 04:00:45 +0000
committerGuenter Bartsch <guenter@users.sourceforge.net>2002-12-18 04:00:45 +0000
commit85632e5177760e08d3d40dcfe9456bef54fcdc2d (patch)
tree23fe16c5ebbc032f620ac5d97706a539982426a2 /src/libw32dll/qt_decoder.c
parent54e7d3ecdb73fbbe09025c7f8b3bdbbe8ea87690 (diff)
downloadxine-lib-85632e5177760e08d3d40dcfe9456bef54fcdc2d.tar.gz
xine-lib-85632e5177760e08d3d40dcfe9456bef54fcdc2d.tar.bz2
first draft of quicktime binary-only codec support
CVS patchset: 3580 CVS date: 2002/12/18 04:00:45
Diffstat (limited to 'src/libw32dll/qt_decoder.c')
-rw-r--r--src/libw32dll/qt_decoder.c1183
1 files changed, 1183 insertions, 0 deletions
diff --git a/src/libw32dll/qt_decoder.c b/src/libw32dll/qt_decoder.c
new file mode 100644
index 000000000..aefed740f
--- /dev/null
+++ b/src/libw32dll/qt_decoder.c
@@ -0,0 +1,1183 @@
+/*
+ * Copyright (C) 2000-2002 the xine project
+ *
+ * This file is part of xine, a free video player.
+ *
+ * xine is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * xine 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ * $Id: qt_decoder.c,v 1.1 2002/12/18 04:00:49 guenter Exp $
+ *
+ * quicktime video/audio decoder plugin, using win32 dlls
+ * most of this code comes directly from MPlayer
+ * authors: A'rpi and Sascha Sommer
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "bswap.h"
+#include "xine_internal.h"
+#include "audio_out.h"
+#include "buffer.h"
+
+#include "qtx/qtxsdk/components.h"
+#include "wine/windef.h"
+#include "wine/ldt_keeper.h"
+
+/*
+#define LOG
+*/
+
+/*
+ *
+ * part 0: common wine stuff
+ * =========================
+ *
+ */
+
+HMODULE WINAPI LoadLibraryA(LPCSTR);
+FARPROC WINAPI GetProcAddress(HMODULE,LPCSTR);
+int WINAPI FreeLibrary(HMODULE);
+
+/* some data is shared inside wine loader.
+ * this mutex seems to avoid some segfaults
+ */
+static pthread_once_t once_control = PTHREAD_ONCE_INIT;
+static pthread_mutex_t win32_codec_mutex;
+extern char *win32_def_path;
+
+static void init_routine(void) {
+
+#ifdef LOG
+ printf ("qt_decoder: init_routine\n");
+#endif
+
+ pthread_mutex_init (&win32_codec_mutex, NULL);
+
+#ifdef LOG
+ printf ("qt_decoder: init_routine completed\n");
+#endif
+}
+
+#define BUFSIZE 1024*1024
+
+/*
+ *
+ * part 1: audio decoder
+ * =====================
+ *
+ */
+
+typedef struct OpaqueSoundConverter* SoundConverter;
+typedef unsigned long UnsignedFixed;
+typedef uint8_t Byte;
+typedef struct SoundComponentData {
+ long flags;
+ OSType format;
+ short numChannels;
+ short sampleSize;
+ UnsignedFixed sampleRate;
+ long sampleCount;
+ Byte * buffer;
+ long reserved;
+}SoundComponentData;
+
+
+typedef int (__cdecl* LPFUNC1)(long flag);
+typedef int (__cdecl* LPFUNC2)(const SoundComponentData *,
+ const SoundComponentData *,
+ SoundConverter *);
+typedef int (__cdecl* LPFUNC3)(SoundConverter sc);
+typedef int (__cdecl* LPFUNC4)(void);
+typedef int (__cdecl* LPFUNC5)(SoundConverter sc, OSType selector,void * infoPtr);
+typedef int (__cdecl* LPFUNC6)(SoundConverter sc,
+ unsigned long inputBytesTarget,
+ unsigned long *inputFrames,
+ unsigned long *inputBytes,
+ unsigned long *outputBytes );
+typedef int (__cdecl* LPFUNC7)(SoundConverter sc,
+ const void *inputPtr,
+ unsigned long inputFrames,
+ void *outputPtr,
+ unsigned long *outputFrames,
+ unsigned long *outputBytes );
+typedef int (__cdecl* LPFUNC8)(SoundConverter sc,
+ void *outputPtr,
+ unsigned long *outputFrames,
+ unsigned long *outputBytes);
+typedef int (__cdecl* LPFUNC9)(SoundConverter sc) ;
+
+#define siDecompressionParams 2002876005 /* siDecompressionParams = FOUR_CHAR_CODE('wave') */
+
+typedef struct {
+ audio_decoder_class_t decoder_class;
+} qta_class_t;
+
+typedef struct qta_decoder_s {
+ audio_decoder_t audio_decoder;
+
+ int codec_initialized;
+ int output_open;
+
+ xine_stream_t *stream;
+
+ HINSTANCE qtml_dll;
+
+ xine_waveformatex wave;
+ uint8_t out_buf[1000000];
+
+ LPFUNC1 InitializeQTML;
+ LPFUNC2 SoundConverterOpen;
+ LPFUNC3 SoundConverterClose;
+ LPFUNC4 TerminateQTML;
+ LPFUNC5 SoundConverterSetInfo;
+ LPFUNC6 SoundConverterGetBufferSizes;
+ LPFUNC7 SoundConverterConvertBuffer;
+ LPFUNC8 SoundConverterEndConversion;
+ LPFUNC9 SoundConverterBeginConversion;
+
+ SoundConverter myConverter;
+ SoundComponentData InputFormatInfo, OutputFormatInfo;
+
+ int InFrameSize;
+ int OutFrameSize;
+ int FramesToGet;
+
+ int frame_size;
+
+ uint8_t data[BUFSIZE];
+ int data_len;
+ int num_frames;
+
+} qta_decoder_t;
+
+#ifdef LOG
+static void qta_hexdump (char *buf, int length) {
+
+ int i;
+
+ printf ("qt_audio: ascii contents>");
+ for (i = 0; i < length; i++) {
+ unsigned char c = buf[i];
+
+ if ((c >= 32) && (c <= 128))
+ printf ("%c", c);
+ else
+ printf (".");
+ }
+ printf ("\n");
+
+ printf ("qt_audio: complete hexdump of package follows:\nqt_audio: 0x0000: ");
+ for (i = 0; i < length; i++) {
+ unsigned char c = buf[i];
+
+ printf ("%02x", c);
+
+ if ((i % 16) == 15)
+ printf ("\nqt_audio: 0x%04x: ", i+1);
+
+ if ((i % 2) == 1)
+ printf (" ");
+
+ }
+ printf ("\n");
+}
+#endif
+
+static void qta_init_driver (qta_decoder_t *this, buf_element_t *buf) {
+
+ int error;
+ unsigned long InputBufferSize=0; /* size of the input buffer */
+ unsigned long OutputBufferSize=0; /* size of the output buffer */
+ unsigned long WantedBufferSize=0; /* the size you want your buffers to be */
+ int mode;
+
+ this->FramesToGet = 0;
+
+#ifdef LOG
+ printf ("qt_audio: init_driver... (trying to lock mutex...)\n");
+#endif
+
+ pthread_mutex_lock(&win32_codec_mutex);
+
+#ifdef LOG
+ printf ("qt_audio: init_driver... (mutex locked)\n");
+#endif
+
+ Setup_LDT_Keeper();
+
+ this->qtml_dll = LoadLibraryA("qtmlClient.dll");
+
+ if (this->qtml_dll == NULL ) {
+ printf ("qt_audio: failed to load dll\n" );
+ return;
+ }
+
+ this->InitializeQTML = (LPFUNC1)GetProcAddress (this->qtml_dll, "InitializeQTML");
+ if ( this->InitializeQTML == NULL ) {
+ printf ("qt_audio: failed geting proc address InitializeQTML\n");
+ pthread_mutex_unlock(&win32_codec_mutex);
+ return;
+ }
+ this->SoundConverterOpen = (LPFUNC2)GetProcAddress (this->qtml_dll, "SoundConverterOpen");
+ if ( this->SoundConverterOpen == NULL ) {
+ printf ("qt_audio: failed getting proc address SoundConverterOpen\n");
+ pthread_mutex_unlock(&win32_codec_mutex);
+ return;
+ }
+ this->SoundConverterClose = (LPFUNC3)GetProcAddress (this->qtml_dll, "SoundConverterClose");
+ if ( this->SoundConverterClose == NULL ) {
+ printf ("qt_audio: failed getting proc address SoundConverterClose\n");
+ pthread_mutex_unlock(&win32_codec_mutex);
+ return;
+ }
+ this->TerminateQTML = (LPFUNC4)GetProcAddress (this->qtml_dll, "TerminateQTML");
+ if ( this->TerminateQTML == NULL ) {
+ printf ("qt_audio: failed getting proc address TerminateQTML\n");
+ pthread_mutex_unlock(&win32_codec_mutex);
+ return;
+ }
+ this->SoundConverterSetInfo = (LPFUNC5)GetProcAddress (this->qtml_dll, "SoundConverterSetInfo");
+ if ( this->SoundConverterSetInfo == NULL ) {
+ printf ("qt_audio: failed getting proc address SoundConverterSetInfo\n");
+ pthread_mutex_unlock(&win32_codec_mutex);
+ return;
+ }
+ this->SoundConverterGetBufferSizes = (LPFUNC6)GetProcAddress (this->qtml_dll, "SoundConverterGetBufferSizes");
+ if ( this->SoundConverterGetBufferSizes == NULL ) {
+ printf ("qt_audio: failed getting proc address SoundConverterGetBufferSizes\n");
+ pthread_mutex_unlock(&win32_codec_mutex);
+ return;
+ }
+ this->SoundConverterConvertBuffer = (LPFUNC7)GetProcAddress (this->qtml_dll, "SoundConverterConvertBuffer");
+ if ( this->SoundConverterConvertBuffer == NULL ) {
+ printf ("qt_audio: failed getting proc address SoundConverterConvertBuffer1\n");
+ pthread_mutex_unlock(&win32_codec_mutex);
+ return;
+ }
+ this->SoundConverterEndConversion = (LPFUNC8)GetProcAddress (this->qtml_dll, "SoundConverterEndConversion");
+ if ( this->SoundConverterEndConversion == NULL ) {
+ printf ("qt_audio: failed getting proc address SoundConverterEndConversion\n");
+ pthread_mutex_unlock(&win32_codec_mutex);
+ return;
+ }
+ this->SoundConverterBeginConversion = (LPFUNC9)GetProcAddress (this->qtml_dll, "SoundConverterBeginConversion");
+ if ( this->SoundConverterBeginConversion == NULL ) {
+ printf ("qt_audio: failed getting proc address SoundConverterBeginConversion\n");
+ pthread_mutex_unlock(&win32_codec_mutex);
+ return;
+ }
+#ifdef LOG
+ printf ("qt_audio: Standard init done you may now call supported functions\n");
+#endif
+
+ error = this->InitializeQTML(6+16);
+#ifdef LOG
+ printf ("qt_audio: InitializeQTML:%i\n",error);
+#endif
+ if (error) {
+ pthread_mutex_unlock(&win32_codec_mutex);
+ return;
+ }
+
+ this->OutputFormatInfo.flags = this->InputFormatInfo.flags = 0;
+ this->OutputFormatInfo.sampleCount = this->InputFormatInfo.sampleCount = 0;
+ this->OutputFormatInfo.buffer = this->InputFormatInfo.buffer = NULL;
+ this->OutputFormatInfo.reserved = this->InputFormatInfo.reserved = 0;
+ this->OutputFormatInfo.numChannels = this->InputFormatInfo.numChannels = this->wave.nChannels;
+ this->InputFormatInfo.sampleSize = this->wave.wBitsPerSample;
+ this->OutputFormatInfo.sampleSize = 16;
+ this->OutputFormatInfo.sampleRate = this->InputFormatInfo.sampleRate = this->wave.nSamplesPerSec;
+
+ switch (buf->type) {
+ case BUF_AUDIO_QDESIGN1:
+ this->InputFormatInfo.format = FOUR_CHAR_CODE('QDM1');
+ break;
+ case BUF_AUDIO_QDESIGN2:
+ this->InputFormatInfo.format = FOUR_CHAR_CODE('QDM2');
+ break;
+ default:
+ printf ("qt_audio: fourcc for buftype %08x ?\n", buf->type);
+ abort ();
+ }
+
+ this->OutputFormatInfo.format = 1313820229; /* FOUR_CHAR_CODE('NONE'); */
+
+#ifdef LOG
+ printf ("qt_audio: input format:\n");
+ qta_hexdump (&this->InputFormatInfo, sizeof (SoundComponentData));
+ printf ("qt_audio: output format:\n");
+ qta_hexdump (&this->OutputFormatInfo, sizeof (SoundComponentData));
+ printf ("qt_audio: stsd atom: \n");
+ qta_hexdump (buf->content, buf->size);
+#endif
+
+ error = this->SoundConverterOpen (&this->InputFormatInfo,
+ &this->OutputFormatInfo,
+ &this->myConverter);
+#ifdef LOG
+ printf ("qt_audio: SoundConverterOpen:%i\n",error);
+#endif
+ if (error) {
+ pthread_mutex_unlock(&win32_codec_mutex);
+ return;
+ }
+
+ if (buf->size > 0x48) {
+ error = this->SoundConverterSetInfo (this->myConverter,
+ siDecompressionParams,
+ buf->content + 0x48);
+#ifdef LOG
+ printf ("qt_audio: SoundConverterSetInfo:%i\n",error);
+#endif
+ if (error) {
+ pthread_mutex_unlock(&win32_codec_mutex);
+
+ return;
+ }
+ }
+
+ WantedBufferSize = this->OutputFormatInfo.numChannels*this->OutputFormatInfo.sampleRate*2;
+ error = this->SoundConverterGetBufferSizes (this->myConverter,
+ WantedBufferSize, &this->FramesToGet,
+ &InputBufferSize, &OutputBufferSize);
+#ifdef LOG
+ printf ("qt_audio: SoundConverterGetBufferSizes:%i\n", error);
+ printf ("qt_audio: WantedBufferSize = %li\n", WantedBufferSize);
+ printf ("qt_audio: InputBufferSize = %li\n", InputBufferSize);
+ printf ("qt_audio: OutputBufferSize = %li\n", OutputBufferSize);
+ printf ("qt_audio: this->FramesToGet = %li\n", this->FramesToGet);
+#endif
+
+ this->InFrameSize = (InputBufferSize+this->FramesToGet-1)/this->FramesToGet;
+ this->OutFrameSize = OutputBufferSize/this->FramesToGet;
+
+#ifdef LOG
+ printf ("qt_audio: FrameSize: %i -> %i\n", this->InFrameSize, this->OutFrameSize);
+#endif
+
+ error = this->SoundConverterBeginConversion (this->myConverter);
+#ifdef LOG
+ printf ("qt_audio: SoundConverterBeginConversion:%i\n",error);
+#endif
+ if (error) {
+ pthread_mutex_unlock(&win32_codec_mutex);
+ return;
+ }
+
+#ifdef LOG
+ printf ("qt_audio: opening output.\n");
+#endif
+
+ switch (this->wave.nChannels) {
+ case 1:
+ mode = AO_CAP_MODE_MONO;
+ break;
+ case 2:
+ mode = AO_CAP_MODE_STEREO;
+ break;
+ case 4:
+ mode = AO_CAP_MODE_4CHANNEL;
+ break;
+ case 5:
+ mode = AO_CAP_MODE_5CHANNEL;
+ break;
+ case 6:
+ mode = AO_CAP_MODE_5_1CHANNEL;
+ break;
+ default:
+ printf ("qt_audio: help, %d channels ?!\n",
+ this->wave.nChannels);
+ abort ();
+ }
+
+ this->frame_size = this->wave.nChannels * this->wave.wBitsPerSample / 8;
+
+ this->output_open = this->stream->audio_out->open(this->stream->audio_out,
+ this->stream,
+ this->wave.wBitsPerSample,
+ this->wave.nSamplesPerSec,
+ mode) ;
+
+ this->codec_initialized = 1;
+
+#ifdef LOG
+ printf ("qt_audio: mutex unlock\n");
+#endif
+
+ pthread_mutex_unlock(&win32_codec_mutex);
+}
+
+static void qta_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) {
+
+ qta_decoder_t *this = (qta_decoder_t *) this_gen;
+
+#ifdef LOG
+ printf ("qt_audio: decode buf=%08x %d bytes flags=%08x pts=%lld\n",
+ buf, buf->size, buf->decoder_flags, buf->pts);
+#endif
+
+ if (buf->decoder_flags & BUF_FLAG_HEADER) {
+
+ memcpy (&this->wave, buf->content, sizeof (xine_waveformatex));
+
+ this->wave.nChannels = buf->decoder_info[3];
+ this->wave.wBitsPerSample = buf->decoder_info[2];
+ this->wave.nSamplesPerSec = buf->decoder_info[1];
+
+#ifdef LOG
+ printf ("qt_audio: header copied\n");
+#endif
+
+ } else if (buf->decoder_flags & BUF_FLAG_SPECIAL) {
+#ifdef LOG
+ printf ("qt_audio: special buffer\n");
+#endif
+
+ if (buf->decoder_info[0] == BUF_SPECIAL_STSD_ATOM) {
+
+#ifdef LOG
+ printf ("qt_audio: got stsd atom -> init codec\n");
+#endif
+
+ if (!this->codec_initialized) {
+ qta_init_driver (this, buf);
+ }
+ }
+ } else {
+
+ memcpy (&this->data[this->data_len], buf->content, buf->size);
+ this->data_len += buf->size;
+
+ if (this->data_len> this->InFrameSize) {
+
+ int num_frames = this->data_len / this->InFrameSize;
+ int out_frames, out_bytes;
+ int error, frames_left, bytes_sent;
+
+ pthread_mutex_lock(&win32_codec_mutex);
+ error = this->SoundConverterConvertBuffer (this->myConverter,
+ this->data,
+ num_frames,
+ this->out_buf,
+ &out_frames, &out_bytes);
+ pthread_mutex_unlock(&win32_codec_mutex);
+
+#ifdef LOG
+ printf ("qt_audio: decoded %d frames => %d frames (error %d)\n",
+ num_frames, out_frames, error);
+#endif
+
+ this->data_len -= this->InFrameSize * num_frames;
+ if (this->data_len>0)
+ memmove (this->data, this->data+num_frames*this->InFrameSize, this->data_len);
+
+
+ frames_left = out_frames;
+ bytes_sent = 0;
+ while (frames_left>0) {
+
+ audio_buffer_t *audio_buffer;
+ int nframes;
+
+ audio_buffer = this->stream->audio_out->get_buffer (this->stream->audio_out);
+
+ nframes = audio_buffer->mem_size / this->frame_size;
+
+ if (nframes > frames_left)
+ nframes = frames_left;
+
+ memcpy (audio_buffer->mem, this->out_buf+bytes_sent, nframes * this->frame_size);
+
+ /* audio_buffer->vpts = buf->pts; */
+ audio_buffer->vpts = 0;
+ audio_buffer->num_frames = nframes;
+
+#ifdef LOG
+ printf ("qt_audio: sending %d frames, %d frames left\n",
+ nframes, frames_left);
+#endif
+
+ this->stream->audio_out->put_buffer (this->stream->audio_out,
+ audio_buffer, this->stream);
+
+ bytes_sent += nframes*this->frame_size;
+ frames_left -= nframes;
+ }
+
+ }
+
+ }
+}
+
+static void qta_reset (audio_decoder_t *this_gen) {
+}
+
+
+static void qta_discontinuity (audio_decoder_t *this_gen) {
+}
+
+static void qta_dispose (audio_decoder_t *this_gen) {
+
+ qta_decoder_t *this = (qta_decoder_t *) this_gen;
+ int error;
+ unsigned long ConvertedFrames=0;
+ unsigned long ConvertedBytes=0;
+ error = this->SoundConverterEndConversion (this->myConverter,NULL,
+ &ConvertedFrames,&ConvertedBytes);
+#ifdef LOG
+ printf ("qt_audio: SoundConverterEndConversion:%i\n",error);
+#endif
+ error = this->SoundConverterClose (this->myConverter);
+#ifdef LOG
+ printf ("qt_audio: SoundConverterClose:%i\n",error);
+#endif
+
+ free (this);
+}
+
+static audio_decoder_t *qta_open_plugin (audio_decoder_class_t *class_gen,
+ xine_stream_t *stream) {
+
+ qta_decoder_t *this ;
+
+ this = (qta_decoder_t *) xine_xmalloc (sizeof (qta_decoder_t));
+
+ this->audio_decoder.decode_data = qta_decode_data;
+ this->audio_decoder.reset = qta_reset;
+ this->audio_decoder.discontinuity = qta_discontinuity;
+ this->audio_decoder.dispose = qta_dispose;
+ this->stream = stream;
+
+ this->output_open = 0;
+
+ return (audio_decoder_t *) this;
+}
+
+/*
+ * qta plugin class
+ */
+
+static char *qta_get_identifier (audio_decoder_class_t *this) {
+ return "qta";
+}
+
+static char *qta_get_description (audio_decoder_class_t *this) {
+ return "quicktime audio decoder plugin";
+}
+
+static void qta_dispose_class (audio_decoder_class_t *this) {
+ free (this);
+}
+
+static void *qta_init_class (xine_t *xine, void *data) {
+
+ qta_class_t *this;
+ config_values_t *cfg;
+
+ pthread_once (&once_control, init_routine);
+
+ this = (qta_class_t *) malloc (sizeof (qta_class_t));
+
+ this->decoder_class.open_plugin = qta_open_plugin;
+ this->decoder_class.get_identifier = qta_get_identifier;
+ this->decoder_class.get_description = qta_get_description;
+ this->decoder_class.dispose = qta_dispose_class;
+
+ cfg = xine->config;
+ win32_def_path = cfg->register_string (cfg, "codec.win32_path",
+ "/usr/lib/win32",
+ _("path to win32 codec dlls"),
+ NULL, 0, NULL, NULL);
+
+ return this;
+}
+
+static uint32_t audio_types[] = {
+ BUF_AUDIO_QDESIGN1, BUF_AUDIO_QDESIGN2, 0
+};
+
+static decoder_info_t qta_dec_info = {
+ audio_types, /* supported types */
+ 5 /* priority */
+};
+
+/*
+ *
+ * part 2: video decoder
+ * =====================
+ *
+ */
+
+typedef struct {
+ video_decoder_class_t decoder_class;
+
+ char *qt_codec_path;
+
+} qtv_class_t;
+
+
+typedef struct qtv_decoder_s {
+ video_decoder_t video_decoder;
+
+ qtv_class_t *cls;
+
+ xine_stream_t *stream;
+
+ HINSTANCE qtml_dll;
+
+ xine_bmiheader bih;
+
+ int codec_initialized;
+
+ uint8_t *plane;
+
+ uint8_t data[BUFSIZE];
+ int data_len;
+
+ /* ComponentDescription desc; */ /* for FindNextComponent() */
+ ComponentInstance ci; /* codec handle */
+ /* CodecInfo cinfo;*/ /* for ImageCodecGetCodecInfo() */
+ /* Component prev=NULL; */
+ /* ComponentResult cres; */
+ CodecCapabilities codeccap; /* for decpar */
+ CodecDecompressParams decpar; /* for ImageCodecPreDecompress() */
+ /* ImageSubCodecDecompressCapabilities icap; // for ImageCodecInitialize() */
+ Rect OutBufferRect; /* the dimensions of our GWorld */
+
+ GWorldPtr OutBufferGWorld; /* a GWorld is some kind of
+ description for a drawing
+ environment */
+ ImageDescriptionHandle framedescHandle;
+
+ /* function pointers */
+
+ Component (*FindNextComponent) (Component prev,
+ ComponentDescription* desc);
+ OSErr (*GetComponentInfo) (Component prev,
+ ComponentDescription* desc,
+ Handle h1,Handle h2,Handle h3);
+ long (*CountComponents) (ComponentDescription* desc);
+ OSErr (*InitializeQTML) (long flags);
+ OSErr (*EnterMovies) (void);
+ ComponentInstance (*OpenComponent) (Component c);
+ ComponentResult (*ImageCodecInitialize) (ComponentInstance ci,
+ ImageSubCodecDecompressCapabilities * cap);
+ ComponentResult (*ImageCodecBeginBand) (ComponentInstance ci,
+ CodecDecompressParams * params,
+ ImageSubCodecDecompressRecord * drp,
+ long flags);
+ ComponentResult (*ImageCodecDrawBand) (ComponentInstance ci,
+ ImageSubCodecDecompressRecord * drp);
+ ComponentResult (*ImageCodecEndBand) (ComponentInstance ci,
+ ImageSubCodecDecompressRecord * drp,
+ OSErr result, long flags);
+ ComponentResult (*ImageCodecGetCodecInfo) (ComponentInstance ci,
+ CodecInfo *info);
+ ComponentResult (*ImageCodecPreDecompress)(ComponentInstance ci,
+ CodecDecompressParams * params);
+ ComponentResult (*ImageCodecBandDecompress)(ComponentInstance ci,
+ CodecDecompressParams * params);
+ PixMapHandle (*GetGWorldPixMap) (GWorldPtr offscreenGWorld);
+ OSErr (*QTNewGWorldFromPtr)(GWorldPtr *gw,
+ OSType pixelFormat,
+ const Rect *boundsRect,
+ CTabHandle cTable,
+ /*GDHandle*/void* aGDevice, /*unused*/
+ GWorldFlags flags,
+ void *baseAddr,
+ long rowBytes);
+ OSErr (*NewHandleClear)(Size byteCount);
+
+} qtv_decoder_t;
+
+#ifdef LOG
+static void qtv_hexdump (char *buf, int length) {
+
+ int i;
+
+ printf ("qt_video: ascii contents>");
+ for (i = 0; i < length; i++) {
+ unsigned char c = buf[i];
+
+ if ((c >= 32) && (c <= 128))
+ printf ("%c", c);
+ else
+ printf (".");
+ }
+ printf ("\n");
+
+ printf ("qt_video: complete hexdump of package follows:\nqt_video: 0x0000: ");
+ for (i = 0; i < length; i++) {
+ unsigned char c = buf[i];
+
+ printf ("%02x", c);
+
+ if ((i % 16) == 15)
+ printf ("\nqt_video: 0x%04x: ", i+1);
+
+ if ((i % 2) == 1)
+ printf (" ");
+
+ }
+ printf ("\n");
+}
+#endif
+
+/*
+ * qt codec loader
+ */
+
+static void qtv_init_driver (qtv_decoder_t *this, buf_element_t *buf) {
+
+ long result = 1;
+ ComponentResult cres;
+ ComponentDescription desc;
+ Component prev=NULL;
+ CodecInfo cinfo; /* for ImageCodecGetCodecInfo() */
+ ImageSubCodecDecompressCapabilities icap; /* for ImageCodecInitialize() */
+ ImageDescription *id;
+
+#ifdef LOG
+ printf ("qt_video: init_driver... (trying to lock mutex...)\n");
+#endif
+
+ pthread_mutex_lock(&win32_codec_mutex);
+
+#ifdef LOG
+ printf ("qt_video: mutex locked\n");
+#endif
+
+ Setup_LDT_Keeper();
+
+ this->qtml_dll = LoadLibraryA("qtmlClient.dll");
+
+ if (this->qtml_dll == NULL ) {
+ printf ("qt_video: failed to load dll\n" );
+ return;
+ }
+
+ this->InitializeQTML = GetProcAddress (this->qtml_dll, "InitializeQTML");
+ this->EnterMovies = GetProcAddress (this->qtml_dll, "EnterMovies");
+ this->FindNextComponent = GetProcAddress (this->qtml_dll, "FindNextComponent");
+ this->CountComponents = GetProcAddress (this->qtml_dll, "CountComponents");
+ this->GetComponentInfo = GetProcAddress (this->qtml_dll, "GetComponentInfo");
+ this->OpenComponent = GetProcAddress (this->qtml_dll, "OpenComponent");
+ this->ImageCodecInitialize = GetProcAddress (this->qtml_dll, "ImageCodecInitialize");
+ this->ImageCodecGetCodecInfo = GetProcAddress (this->qtml_dll, "ImageCodecGetCodecInfo");
+ this->ImageCodecBeginBand = GetProcAddress (this->qtml_dll, "ImageCodecBeginBand");
+ this->ImageCodecPreDecompress = GetProcAddress (this->qtml_dll, "ImageCodecPreDecompress");
+ this->ImageCodecBandDecompress = GetProcAddress (this->qtml_dll, "ImageCodecBandDecompress");
+ this->GetGWorldPixMap = GetProcAddress (this->qtml_dll, "GetGWorldPixMap");
+ this->QTNewGWorldFromPtr = GetProcAddress (this->qtml_dll, "QTNewGWorldFromPtr");
+ this->NewHandleClear = GetProcAddress (this->qtml_dll, "NewHandleClear");
+
+ if (!this->InitializeQTML || !this->EnterMovies || !this->FindNextComponent
+ || !this->ImageCodecBandDecompress){
+ printf ("qt_video: invalid qt DLL!\n");
+ pthread_mutex_unlock(&win32_codec_mutex);
+ return;
+ }
+
+#ifdef LOG
+ printf ("qt_video: calling InitializeQTML...\n");
+#endif
+
+ result = this->InitializeQTML(6+16);
+ /* result=InitializeQTML(0); */
+#ifdef LOG
+ printf("qt_video: InitializeQTML returned %d\n",result);
+#endif
+ /* result=EnterMovies(); */
+ /* printf("EnterMovies->%d\n",result); */
+
+ memset(&desc,0,sizeof(desc));
+ desc.componentType= (((unsigned char)'i')<<24)|
+ (((unsigned char)'m')<<16)|
+ (((unsigned char)'d')<<8)|
+ (((unsigned char)'c'));
+ desc.componentSubType=
+ (((unsigned char)'S'<<24))|
+ (((unsigned char)'V')<<16)|
+ (((unsigned char)'Q')<<8)|
+ (((unsigned char)'3'));
+
+ desc.componentManufacturer=0;
+ desc.componentFlags=0;
+ desc.componentFlagsMask=0;
+
+#ifdef LOG
+ printf("qt_video: Count = %d\n", this->CountComponents(&desc));
+#endif
+
+ prev = this->FindNextComponent(NULL,&desc);
+ if(!prev){
+ printf("Cannot find requested component\n");
+ pthread_mutex_unlock(&win32_codec_mutex);
+ return;
+ }
+#ifdef LOG
+ printf ("qt_video: Found it! ID = 0x%X\n",prev);
+#endif
+
+ this->ci = this->OpenComponent(prev);
+ printf ("qt_video: this->ci=%p\n",this->ci);
+
+ memset (&icap,0,sizeof(icap));
+ cres = this->ImageCodecInitialize (this->ci, &icap);
+#ifdef LOG
+ printf ("qt_video: ImageCodecInitialize->%p size=%d (%d)\n",
+ cres,icap.recordSize,icap.decompressRecordSize);
+#endif
+
+ memset(&cinfo,0,sizeof(cinfo));
+ cres = this->ImageCodecGetCodecInfo (this->ci, &cinfo);
+#ifdef LOG
+ printf ("qt_video: Flags: compr: 0x%X decomp: 0x%X format: 0x%X\n",
+ cinfo.compressFlags, cinfo.decompressFlags, cinfo.formatFlags);
+ printf ("qt_video: Codec name: %.*s\n", ((unsigned char*)&cinfo.typeName)[0],
+ ((unsigned char*)&cinfo.typeName)+1);
+#endif
+
+ /* make a yuy2 gworld */
+ this->OutBufferRect.top = 0;
+ this->OutBufferRect.left = 0;
+ this->OutBufferRect.right = this->bih.biWidth;
+ this->OutBufferRect.bottom = this->bih.biHeight;
+
+#ifdef LOG
+ printf ("qt_video: image size %d x %d\n",
+ this->bih.biWidth, this->bih.biHeight);
+
+ printf ("qt_video: stsd (%d bytes):\n", buf->size) ;
+
+ qtv_hexdump (buf->content, buf->size);
+#endif
+
+ {
+ uint8_t *stdata = buf->content + 20;
+ int stdata_len = buf->size - 24;
+
+ id=malloc (8+stdata_len) ; /* trak->stdata_len); */
+ id->idSize = 8+stdata_len;
+ id->cType = (((unsigned char)'S'<<24))|
+ (((unsigned char)'V')<<16)|
+ (((unsigned char)'Q')<<8)|
+ (((unsigned char)'3')); /* bswap_32(trak->fourcc); */
+ id->version = BE_16 (stdata+ 8);
+ id->revisionLevel = BE_16 (stdata+10);
+ id->vendor = BE_32 (stdata+12);
+ id->temporalQuality = BE_32 (stdata+16);
+ id->spatialQuality = BE_32 (stdata+20);
+ id->width = BE_16 (stdata+24);
+ id->height = BE_16 (stdata+26);
+ id->hRes = BE_32 (stdata+28);
+ id->vRes = BE_32 (stdata+32);
+ id->dataSize = BE_32 (stdata+36);
+ id->frameCount = BE_16 (stdata+40);
+ memcpy(&id->name,stdata+42,32);
+ id->depth = BE_16 (stdata+74);
+ id->clutID = BE_16 (stdata+76);
+ if (stdata_len>78)
+ memcpy (((char*)&id->clutID)+2, stdata+78, stdata_len-78);
+
+#ifdef LOG
+ printf ("qt_video: id (%d bytes)\n", stdata_len);
+ qtv_hexdump (id, stdata_len);
+#endif
+
+ }
+
+#ifdef LOG
+ printf ("qt_video: ImageDescription size: %d\n",
+ id->idSize);
+
+ qtv_hexdump (id, id->idSize);
+#endif
+
+ this->framedescHandle = (ImageDescriptionHandle) this->NewHandleClear (id->idSize);
+
+#ifdef LOG
+ printf ("qt_video: framedescHandle = %x\n",
+ this->framedescHandle);
+#endif
+
+ memcpy (*this->framedescHandle, id, id->idSize);
+
+ /*
+ * alloc video plane
+ */
+
+ this->plane = malloc (this->bih.biWidth * this->bih.biHeight * 3);
+
+ result = this->QTNewGWorldFromPtr(&this->OutBufferGWorld,
+ kYUVSPixelFormat, /*pixel format of new GWorld==YUY2 */
+ &this->OutBufferRect, /*we should benchmark if yvu9 is faster for svq3, too */
+ 0,
+ 0,
+ 0,
+ this->plane,
+ this->bih.biWidth*2);
+
+#ifdef LOG
+ printf ("qt_video: NewGWorldFromPtr returned:%d\n",
+ 65536-(result&0xffff));
+#endif
+
+ this->decpar.imageDescription = this->framedescHandle;
+ this->decpar.startLine = 0;
+ this->decpar.stopLine = (**this->framedescHandle).height;
+ this->decpar.frameNumber = 1;
+ this->decpar.matrixFlags = 0;
+ this->decpar.matrixType = 0;
+ this->decpar.matrix = 0;
+ this->decpar.capabilities = &this->codeccap;
+ this->decpar.accuracy = codecNormalQuality;
+ this->decpar.port = this->OutBufferGWorld;
+ this->decpar.srcRect = this->OutBufferRect;
+
+ this->decpar.transferMode = srcCopy;
+ this->decpar.dstPixMap = **this->GetGWorldPixMap (this->OutBufferGWorld);/*destPixmap; */
+
+ cres = this->ImageCodecPreDecompress (this->ci, &this->decpar);
+#ifdef LOG
+ printf ("qt_video: ImageCodecPreDecompress cres=0x%X\n", cres);
+#endif
+
+ this->data_len = 0;
+
+ this->codec_initialized = 1;
+
+ pthread_mutex_unlock(&win32_codec_mutex);
+
+}
+
+static void qtv_decode_data (video_decoder_t *this_gen, buf_element_t *buf) {
+ qtv_decoder_t *this = (qtv_decoder_t *) this_gen;
+
+#ifdef LOG
+ printf ("qt_video: decode_data, flags=0x%08x, len=%d, pts=%lld ...\n",
+ buf->decoder_flags, buf->size, buf->pts);
+#endif
+
+ if (buf->decoder_flags & BUF_FLAG_HEADER) {
+
+#ifdef LOG
+ printf ("qt_video: copying bih\n");
+#endif
+
+ memcpy (&this->bih, buf->content, sizeof (xine_bmiheader));
+
+ } else if (buf->decoder_flags & BUF_FLAG_SPECIAL) {
+#ifdef LOG
+ printf ("qt_video: special buffer\n");
+#endif
+
+ if (buf->decoder_info[0] == BUF_SPECIAL_STSD_ATOM) {
+
+#ifdef LOG
+ printf ("qt_video: got stsd atom -> init codec\n");
+#endif
+
+ if (!this->codec_initialized) {
+ qtv_init_driver (this, buf);
+ }
+ }
+ } else {
+
+#ifdef LOG
+ printf ("qt_video: actual image data\n");
+#endif
+
+ memcpy (&this->data[this->data_len], buf->content, buf->size);
+ this->data_len += buf->size;
+
+#ifdef LOG
+ printf ("qt_video: got %d bytes in buffer\n", this->data_len);
+#endif
+
+ if (buf->decoder_flags & BUF_FLAG_FRAME_END) {
+
+ ComponentResult cres;
+ vo_frame_t *img;
+
+ pthread_mutex_lock(&win32_codec_mutex);
+
+ this->decpar.data = this->data;
+ this->decpar.bufferSize = this->data_len;
+ (**this->framedescHandle).dataSize=this->data_len;
+
+ cres = this->ImageCodecBandDecompress (this->ci, &this->decpar);
+
+ ++this->decpar.frameNumber;
+
+ pthread_mutex_unlock(&win32_codec_mutex);
+
+ if (cres&0xFFFF){
+ printf("qt_video: ImageCodecBandDecompress cres=0x%X (-0x%X) %d :(\n",
+ cres,-cres,cres);
+ }
+
+ img = this->stream->video_out->get_frame (this->stream->video_out,
+ this->bih.biWidth,
+ this->bih.biHeight,
+ 42,
+ XINE_IMGFMT_YUY2,
+ VO_BOTH_FIELDS);
+
+ img->pts = buf->pts;
+ img->duration = buf->decoder_info[0];
+ img->bad_frame = 0;
+
+ xine_fast_memcpy (img->base[0], this->plane,
+ this->bih.biWidth*this->bih.biHeight*2);
+
+ img->draw(img, this->stream);
+ img->free(img);
+
+ this->data_len = 0;
+ }
+ }
+
+#ifdef LOG
+ printf ("qt_video: decode_data...done\n");
+#endif
+}
+
+static void qtv_flush (video_decoder_t *this_gen) {
+ /* qtv_decoder_t *this = (qtv_decoder_t *) this_gen; */
+
+#ifdef LOG
+ printf ("qt_video: flush\n");
+#endif
+
+}
+
+static void qtv_reset (video_decoder_t *this_gen) {
+ /* qtv_decoder_t *this = (qtv_decoder_t *) this_gen; */
+
+}
+
+static void qtv_discontinuity (video_decoder_t *this_gen) {
+ /* qtv_decoder_t *this = (qtv_decoder_t *) this_gen; */
+
+}
+
+static void qtv_dispose (video_decoder_t *this_gen) {
+
+ qtv_decoder_t *this = (qtv_decoder_t *) this_gen;
+
+#ifdef LOG
+ printf ("qt_video: close\n");
+#endif
+
+ free (this);
+}
+
+static video_decoder_t *qtv_open_plugin (video_decoder_class_t *class_gen,
+ xine_stream_t *stream) {
+
+ qtv_class_t *cls = (qtv_class_t *) class_gen;
+ qtv_decoder_t *this ;
+
+ this = (qtv_decoder_t *) xine_xmalloc (sizeof (qtv_decoder_t));
+
+ this->video_decoder.decode_data = qtv_decode_data;
+ this->video_decoder.flush = qtv_flush;
+ this->video_decoder.reset = qtv_reset;
+ this->video_decoder.discontinuity = qtv_discontinuity;
+ this->video_decoder.dispose = qtv_dispose;
+ this->stream = stream;
+ this->cls = cls;
+
+ return &this->video_decoder;
+}
+
+
+/*
+ * qtv plugin class
+ */
+
+static char *qtv_get_identifier (video_decoder_class_t *this) {
+ return "qtvdec";
+}
+
+static char *qtv_get_description (video_decoder_class_t *this) {
+ return "quicktime binary-only codec based video decoder plugin";
+}
+
+static void qtv_dispose_class (video_decoder_class_t *this) {
+ free (this);
+}
+
+/*
+ * some fake functions to make qt codecs happy
+ */
+
+#if 0
+static void codec_path_cb (void *data, xine_cfg_entry_t *cfg) {
+ qtv_class_t *this = (qt_class_t *) data;
+
+ this->qt_codec_path = cfg->str_value;
+}
+#endif
+
+static void *qtv_init_class (xine_t *xine, void *data) {
+
+ qtv_class_t *this;
+ config_values_t *cfg = xine->config;
+
+ win32_def_path = cfg->register_string (cfg, "codec.win32_path", "/usr/lib/win32",
+ _("path to win32 codec dlls"),
+ NULL, 0, NULL, NULL);
+
+ printf ("qtv_init_class...\n");
+
+ pthread_once (&once_control, init_routine);
+
+ printf ("qtv_init_class... done\n");
+
+ this = (qtv_class_t *) xine_xmalloc (sizeof (qtv_class_t));
+
+ this->decoder_class.open_plugin = qtv_open_plugin;
+ this->decoder_class.get_identifier = qtv_get_identifier;
+ this->decoder_class.get_description = qtv_get_description;
+ this->decoder_class.dispose = qtv_dispose_class;
+
+ return this;
+}
+
+/*
+ * exported plugin catalog entry
+ */
+
+static uint32_t qtv_supported_types[] = { BUF_VIDEO_SORENSON_V3, 0 };
+
+static decoder_info_t qtv_dec_info = {
+ qtv_supported_types, /* supported types */
+ 6 /* priority */
+};
+
+plugin_info_t xine_plugin_info[] = {
+ /* type, API, "name", version, special_info, init_function */
+ { PLUGIN_VIDEO_DECODER, 13, "qtv", XINE_VERSION_CODE, &qtv_dec_info, qtv_init_class },
+ { PLUGIN_AUDIO_DECODER, 12, "qta", XINE_VERSION_CODE, &qta_dec_info, qta_init_class },
+ { PLUGIN_NONE, 0, "", 0, NULL, NULL }
+};
+