mirror of
https://gitlab.winehq.org/wine/wine.git
synced 2025-08-28 18:23:54 +02:00
229 lines
6.7 KiB
C
229 lines
6.7 KiB
C
/*
|
|
* Copyright 2024 Rémi Bernon for CodeWeavers
|
|
*
|
|
* 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 St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
*/
|
|
|
|
#if 0
|
|
#pragma makedep unix
|
|
#endif
|
|
|
|
#include "config.h"
|
|
|
|
#ifdef HAVE_FFMPEG
|
|
|
|
#include "unix_private.h"
|
|
#include "wine/debug.h"
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(dmo);
|
|
|
|
static UINT64 seek_callback;
|
|
static UINT64 read_callback;
|
|
|
|
int64_t unix_seek_callback( void *opaque, int64_t offset, int whence )
|
|
{
|
|
struct seek_callback_params params = {.dispatch = {.callback = seek_callback}, .context = (UINT_PTR)opaque};
|
|
struct stream_context *context = opaque;
|
|
void *ret_ptr;
|
|
ULONG ret_len;
|
|
int status;
|
|
|
|
TRACE( "opaque %p, offset %#"PRIx64", whence %#x\n", opaque, offset, whence );
|
|
|
|
if (whence == AVSEEK_SIZE) return context->length;
|
|
if (whence == SEEK_END) offset += context->length;
|
|
if (whence == SEEK_CUR) offset += context->position;
|
|
if ((UINT64)offset > context->length) offset = context->length;
|
|
|
|
if (offset / context->capacity != context->position / context->capacity)
|
|
{
|
|
for (;;)
|
|
{
|
|
/* seek stream to multiples of buffer capacity */
|
|
params.offset = (offset / context->capacity) * context->capacity;
|
|
status = KeUserDispatchCallback( ¶ms.dispatch, sizeof(params), &ret_ptr, &ret_len );
|
|
if (status || ret_len != sizeof(UINT64)) return AVERROR( EINVAL );
|
|
if (*(UINT64 *)ret_ptr == params.offset) break;
|
|
offset = *(UINT64 *)ret_ptr;
|
|
}
|
|
context->size = 0;
|
|
}
|
|
|
|
context->position = offset;
|
|
return offset;
|
|
}
|
|
|
|
static int stream_context_read( struct stream_context *context )
|
|
{
|
|
struct read_callback_params params = {.dispatch = {.callback = read_callback}, .context = (UINT_PTR)context};
|
|
void *ret_ptr;
|
|
ULONG ret_len;
|
|
int status;
|
|
|
|
params.size = context->capacity;
|
|
status = KeUserDispatchCallback( ¶ms.dispatch, sizeof(params), &ret_ptr, &ret_len );
|
|
if (status || ret_len != sizeof(ULONG)) return AVERROR( EINVAL );
|
|
context->size = *(ULONG *)ret_ptr;
|
|
return 0;
|
|
}
|
|
|
|
int unix_read_callback( void *opaque, uint8_t *buffer, int size )
|
|
{
|
|
struct stream_context *context = opaque;
|
|
int ret, total = 0;
|
|
|
|
if (!(size = min( (UINT64)size, context->length - context->position ))) return AVERROR_EOF;
|
|
|
|
while (size)
|
|
{
|
|
int step, buffer_offset = context->position % context->capacity;
|
|
|
|
if (!context->size && (ret = stream_context_read( context )) < 0) return ret;
|
|
if (!(step = min( size, context->size - buffer_offset ))) break;
|
|
memcpy( buffer, context->buffer + buffer_offset, step );
|
|
buffer += step;
|
|
total += step;
|
|
size -= step;
|
|
|
|
context->position += step;
|
|
if (!(context->position % context->capacity)) context->size = 0;
|
|
}
|
|
|
|
if (!total) return AVERROR_EOF;
|
|
return total;
|
|
}
|
|
|
|
static void vlog( void *ctx, int level, const char *fmt, va_list va_args )
|
|
{
|
|
enum __wine_debug_class dbcl = __WINE_DBCL_TRACE;
|
|
if (level <= AV_LOG_ERROR) dbcl = __WINE_DBCL_ERR;
|
|
if (level <= AV_LOG_WARNING) dbcl = __WINE_DBCL_WARN;
|
|
wine_dbg_vlog( dbcl, __wine_dbch___default, __func__, fmt, va_args );
|
|
}
|
|
|
|
static const char *debugstr_version( UINT version )
|
|
{
|
|
return wine_dbg_sprintf("%u.%u.%u", AV_VERSION_MAJOR(version), AV_VERSION_MINOR(version), AV_VERSION_MICRO(version));
|
|
}
|
|
|
|
static NTSTATUS process_attach( void *arg )
|
|
{
|
|
struct process_attach_params *params = arg;
|
|
const AVInputFormat *demuxer;
|
|
void *opaque;
|
|
|
|
TRACE( "FFmpeg support:\n" );
|
|
TRACE( " avutil version %s\n", debugstr_version( avutil_version() ) );
|
|
TRACE( " avformat version %s\n", debugstr_version( avformat_version() ) );
|
|
|
|
TRACE( "available demuxers:\n" );
|
|
for (opaque = NULL; (demuxer = av_demuxer_iterate( &opaque ));)
|
|
{
|
|
TRACE( " %s (%s)\n", demuxer->name, demuxer->long_name );
|
|
if (demuxer->extensions) TRACE( " extensions: %s\n", demuxer->extensions );
|
|
if (demuxer->mime_type) TRACE( " mime_types: %s\n", demuxer->mime_type );
|
|
}
|
|
|
|
av_log_set_callback( vlog );
|
|
|
|
seek_callback = params->seek_callback;
|
|
read_callback = params->read_callback;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
const unixlib_entry_t __wine_unix_call_funcs[] =
|
|
{
|
|
#define X( name ) [unix_##name] = name
|
|
X( process_attach ),
|
|
|
|
X( demuxer_check ),
|
|
X( demuxer_create ),
|
|
X( demuxer_destroy ),
|
|
X( demuxer_read ),
|
|
X( demuxer_seek ),
|
|
X( demuxer_stream_lang ),
|
|
X( demuxer_stream_name ),
|
|
X( demuxer_stream_type ),
|
|
};
|
|
|
|
C_ASSERT(ARRAY_SIZE(__wine_unix_call_funcs) == unix_funcs_count);
|
|
|
|
#ifdef _WIN64
|
|
|
|
typedef ULONG PTR32;
|
|
|
|
static NTSTATUS wow64_demuxer_create( void *arg )
|
|
{
|
|
struct
|
|
{
|
|
PTR32 url;
|
|
PTR32 context;
|
|
struct winedmo_demuxer demuxer;
|
|
char mime_type[256];
|
|
UINT32 stream_count;
|
|
INT64 duration;
|
|
} *params32 = arg;
|
|
struct demuxer_create_params params;
|
|
NTSTATUS status;
|
|
|
|
params.url = UintToPtr( params32->url );
|
|
params.context = UintToPtr( params32->context );
|
|
if ((status = demuxer_create( ¶ms ))) return status;
|
|
params32->demuxer = params.demuxer;
|
|
memcpy( params32->mime_type, params.mime_type, 256 );
|
|
params32->stream_count = params.stream_count;
|
|
params32->duration = params.duration;
|
|
|
|
return status;
|
|
}
|
|
|
|
static NTSTATUS wow64_demuxer_destroy( void *arg )
|
|
{
|
|
struct
|
|
{
|
|
struct winedmo_demuxer demuxer;
|
|
PTR32 context;
|
|
} *params32 = arg;
|
|
struct demuxer_create_params params;
|
|
NTSTATUS status;
|
|
|
|
params.demuxer = params32->demuxer;
|
|
if ((status = demuxer_destroy( ¶ms ))) return status;
|
|
params32->context = PtrToUint( params.context );
|
|
|
|
return status;
|
|
}
|
|
|
|
const unixlib_entry_t __wine_unix_call_wow64_funcs[] =
|
|
{
|
|
#define X64( name ) [unix_##name] = wow64_##name
|
|
X( process_attach ),
|
|
|
|
X( demuxer_check ),
|
|
X64( demuxer_create ),
|
|
X64( demuxer_destroy ),
|
|
X( demuxer_read ),
|
|
X( demuxer_seek ),
|
|
X( demuxer_stream_lang ),
|
|
X( demuxer_stream_name ),
|
|
X( demuxer_stream_type ),
|
|
};
|
|
|
|
C_ASSERT(ARRAY_SIZE(__wine_unix_call_wow64_funcs) == unix_funcs_count);
|
|
|
|
#endif /* _WIN64 */
|
|
|
|
#endif /* HAVE_FFMPEG */
|