Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
268 lines (224 sloc) 6.44 KB
/*****************************************************************************
*
* Avi Import Component dataref interface for libavformat
*
* Copyright(C) 2006 Christoph Naegeli <chn1@mac.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
****************************************************************************/
#include <QuickTime/QuickTime.h>
#include <libavformat/avformat.h>
#include <libavformat/avio_internal.h>
struct _dataref_private {
Handle dataRef;
OSType dataRefType;
DataHandler dh;
int64_t pos;
int64_t size;
unsigned char supportsWideOffsets;
};
typedef struct _dataref_private dataref_private;
/* DataRef Wrapper for QuickTime */
static int dataref_update_filesize(dataref_private *private)
{
wide fsize;
ComponentResult result = DataHGetFileSize64(private->dh, &fsize);
if(result == noErr) {
private->size = (int64_t)fsize.lo;
private->size += (int64_t)fsize.hi << 32;
// Our data handler supports wide offsets. Remember for later use.
private->supportsWideOffsets = 1;
} else {
long size32;
result = DataHGetFileSize(private->dh, &size32);
require_noerr(result, bail);
private->size = size32;
}
bail:
return result;
}
/* !!! THIS FUNCTION ASSUMES h->priv_data IS VALID in contrary to the other open functions
* found in ffmpeg */
static int dataref_open(URLContext *h, const char *filename, int flags)
{
ComponentResult result;
dataref_private *private;
long access = 0;
if((flags & URL_RDWR) == URL_RDWR) {
access = kDataHCanRead | kDataHCanWrite;
} else if(flags & URL_WRONLY) {
access = kDataHCanWrite;
} else {
access = kDataHCanRead;
}
private = h->priv_data;
result = OpenAComponent(GetDataHandler(private->dataRef, private->dataRefType, access), &private->dh);
require_noerr(result,bail);
result = DataHSetDataRef(private->dh, private->dataRef);
require_noerr(result,bail);
if(access & kDataHCanRead) {
result = DataHOpenForRead(private->dh);
require_noerr(result,bail);
}
if(access & kDataHCanWrite) {
result = DataHOpenForWrite(private->dh);
require_noerr(result,bail);
}
private->pos = 0ll;
private->size = 0ll;
result = dataref_update_filesize(private);
require_noerr(result,bail);
bail:
return result;
} /* dataref_open() */
static int dataref_read(URLContext *h, unsigned char *buf, int size)
{
int result;
dataref_private *p = (dataref_private*)h->priv_data;
int read;
if (p->pos + size > p->size) {
// it tried to read past the end
// but since we cache the size, it might be wrong
// try to update the size before clipping the request
dataref_update_filesize(p);
}
if (p->pos >= p->size)
return 0; // can't read past the end
else
read = FFMIN(size, p->size - p->pos);
if(p->supportsWideOffsets) {
wide offset;
offset.hi = p->pos >> 32;
offset.lo = (UInt32)p->pos;
result = DataHScheduleData64(p->dh, (Ptr)buf, &offset, (long)read, 0, NULL, NULL);
if (result == badComponentSelector && offset.hi == 0) {
result = DataHScheduleData(p->dh, (Ptr)buf, offset.lo, (long)read, 0, NULL, NULL);
}
} else {
result = DataHScheduleData(p->dh, (Ptr)buf, (long)p->pos, (long)read, 0, NULL, NULL);
}
if(result != noErr) {
read = -1;
goto bail;
}
p->pos += read;
bail:
return (int)read;
} /* dataref_read() */
static int dataref_write(URLContext *h, const unsigned char *buf, int size)
{
int result;
int written = size;
dataref_private *p = (dataref_private*)h->priv_data;
if(p->supportsWideOffsets) {
wide offset;
offset.hi = p->pos >> 32;
offset.lo = (UInt32)p->pos;
result = DataHWrite64(p->dh, (Ptr)buf, &offset, size, NULL, 0);
} else {
result = DataHWrite(p->dh, (Ptr)buf, (long)p->pos, size, NULL, 0);
}
if(result != noErr) {
written = -1;
goto bail;
}
p->pos += written;
bail:
return written;
} /* dataref_write() */
static int64_t dataref_seek(URLContext *h, int64_t pos, int whence)
{
dataref_private *p = (dataref_private*)h->priv_data;
switch(whence) {
case SEEK_SET:
p->pos = pos;
break;
case SEEK_CUR:
p->pos += pos;
break;
case SEEK_END:
dataref_update_filesize(p);
p->pos = p->size + pos;
break;
case AVSEEK_SIZE:
dataref_update_filesize(p);
return p->size;
default:
return -1;
}
return p->pos;
} /* dataref_seek() */
static int dataref_close(URLContext *h)
{
dataref_private *p = (dataref_private*)h->priv_data;
CloseComponent(p->dh);
p->dh = 0;
p->pos = 0;
p->size = 0;
av_free(p);
h->priv_data = NULL;
return 0;
} /* dataref_close() */
URLProtocol dataref_protocol = {
"Data Ref",
dataref_open,
dataref_read,
dataref_write,
dataref_seek,
dataref_close,
};
/* This is the public function to open bytecontext withs datarefs */
OSStatus url_open_dataref(AVIOContext **pb, Handle dataRef, OSType dataRefType, DataHandler *dataHandler, Boolean *wideSupport, int64_t *dataSize)
{
URLContext *uc;
URLProtocol *up;
OSStatus err;
dataref_private *private;
private = av_mallocz(sizeof(dataref_private));
private->dataRef = dataRef;
private->dataRefType = dataRefType;
up = &dataref_protocol;
//FIXME use url_alloc() with better fake protocol, and avoid using avio_internal
uc = av_mallocz(sizeof(URLContext));
if(!uc) {
err = -ENOMEM;
return err;
}
uc->filename = NULL;
uc->prot = up;
uc->flags = URL_RDONLY; // we're just using the read access...
uc->is_streamed = 0; // not streamed...
uc->max_packet_size = 0; // stream file
uc->priv_data = private;
uc->is_connected = 1;
err = up->url_open(uc, uc->filename, URL_RDONLY);
if(err < 0) {
av_free(uc);
return err;
}
err = ffio_fdopen(pb, uc);
if(err < 0) {
ffurl_close(uc);
return err;
}
if(dataHandler)
*dataHandler = private->dh;
if(wideSupport)
*wideSupport = private->supportsWideOffsets;
if(dataSize)
*dataSize = private->size;
return noErr;
} /* url_open_dataref() */