Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=57204
-- v2: winedmo: Convert H264 streams to Annex B format. winedmo: Pass demuxer packets through the bitstream filters. winedmo: Create bitstream filters for demuxer streams. winedmo: Move the last packet to the demuxer struct. winedmo: Allocate a dedicated demuxer structure. winedmo: Simplify demuxer creation error handling. winedmo: Hoist the demuxer input format. mfsrcsnk: Serialize stream sample requests with the state callbacks.
From: Rémi Bernon rbernon@codeweavers.com
Removing the now unnecessary pending_state variable. We always keep as many async read requests as there's tokens in the queue. --- dlls/mfsrcsnk/media_source.c | 65 +++++++++++++++++++++++------------- 1 file changed, 42 insertions(+), 23 deletions(-)
diff --git a/dlls/mfsrcsnk/media_source.c b/dlls/mfsrcsnk/media_source.c index 7bb7f049428..ac5f013d9cd 100644 --- a/dlls/mfsrcsnk/media_source.c +++ b/dlls/mfsrcsnk/media_source.c @@ -209,6 +209,7 @@ static HRESULT async_start_params_create(IMFPresentationDescriptor *descriptor, struct media_stream { IMFMediaStream IMFMediaStream_iface; + IMFAsyncCallback async_request_iface; LONG refcount;
IMFMediaSource *source; @@ -257,7 +258,7 @@ struct media_source SOURCE_RUNNING, SOURCE_SHUTDOWN, } state; - UINT pending_state; + UINT pending_reads; };
static struct media_source *media_source_from_IMFMediaSource(IMFMediaSource *iface) @@ -265,7 +266,7 @@ static struct media_source *media_source_from_IMFMediaSource(IMFMediaSource *ifa return CONTAINING_RECORD(iface, struct media_source, IMFMediaSource_iface); }
-static HRESULT media_stream_send_sample(struct media_stream *stream, IMFSample *sample, IUnknown *token) +static void media_stream_send_sample(struct media_stream *stream, IMFSample *sample, IUnknown *token) { HRESULT hr = S_OK;
@@ -273,7 +274,7 @@ static HRESULT media_stream_send_sample(struct media_stream *stream, IMFSample * hr = IMFMediaEventQueue_QueueEventParamUnk(stream->queue, MEMediaSample, &GUID_NULL, S_OK, (IUnknown *)sample);
- return hr; + if (FAILED(hr)) ERR("Failed to send stream %p sample, hr %#lx\n", stream, hr); }
static struct media_stream *media_stream_from_index(struct media_source *source, UINT index) @@ -299,9 +300,9 @@ static HRESULT media_source_send_sample(struct media_source *source, UINT index,
if (SUCCEEDED(hr = object_queue_pop(&stream->tokens, &token))) { - hr = media_stream_send_sample(stream, sample, token); + media_stream_send_sample(stream, sample, token); if (token) IUnknown_Release(token); - return hr; + return S_OK; }
if (FAILED(hr = object_queue_push(&stream->samples, (IUnknown *)sample))) @@ -328,10 +329,9 @@ static void queue_media_source_read(struct media_source *source) { HRESULT hr;
- if (source->pending_state) - return; if (FAILED(hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &source->async_read_iface, NULL))) ERR("Failed to queue async read for source %p, hr %#lx\n", source, hr); + source->pending_reads++; }
static void media_stream_start(struct media_stream *stream, UINT index, const PROPVARIANT *position) @@ -358,8 +358,8 @@ static void media_stream_start(struct media_stream *stream, UINT index, const PR if (position->vt == VT_EMPTY && stream->active) { struct list samples = LIST_INIT(samples); - struct object_entry *object, *next; IMFSample *sample; + UINT token_count;
list_move_head(&samples, &stream->samples); while (object_queue_pop(&samples, (IUnknown **)&sample) != E_PENDING) @@ -368,7 +368,8 @@ static void media_stream_start(struct media_stream *stream, UINT index, const PR IMFSample_Release(sample); }
- LIST_FOR_EACH_ENTRY_SAFE(object, next, &stream->tokens, struct object_entry, entry) + token_count = list_count(&stream->tokens); + while (source->pending_reads < token_count) queue_media_source_read(source); } } @@ -451,7 +452,6 @@ static HRESULT media_source_async_start(struct media_source *source, IMFAsyncRes params = async_start_params_from_IUnknown(state);
EnterCriticalSection(&source->cs); - source->pending_state--;
if (FAILED(hr = media_source_start(source, params->descriptor, ¶ms->format, ¶ms->position))) WARN("Failed to start source %p, hr %#lx\n", source, hr); @@ -499,7 +499,6 @@ static HRESULT media_source_async_stop(struct media_source *source, IMFAsyncResu HRESULT hr;
EnterCriticalSection(&source->cs); - source->pending_state--;
if (FAILED(hr = media_source_stop(source))) WARN("Failed to stop source %p, hr %#lx\n", source, hr); @@ -544,7 +543,6 @@ static HRESULT media_source_async_pause(struct media_source *source, IMFAsyncRes HRESULT hr;
EnterCriticalSection(&source->cs); - source->pending_state--;
if (FAILED(hr = media_source_pause(source))) WARN("Failed to pause source %p, hr %#lx\n", source, hr); @@ -662,6 +660,7 @@ static HRESULT media_source_async_read(struct media_source *source, IMFAsyncResu HRESULT hr;
EnterCriticalSection(&source->cs); + source->pending_reads--;
if (FAILED(hr = media_source_read(source))) WARN("Failed to request sample, hr %#lx\n", hr); @@ -801,11 +800,33 @@ static HRESULT WINAPI media_stream_GetStreamDescriptor(IMFMediaStream* iface, IM return hr; }
+static HRESULT media_stream_async_request(struct media_stream *stream, IMFAsyncResult *result) +{ + struct media_source *source = media_source_from_IMFMediaSource(stream->source); + IUnknown *token = IMFAsyncResult_GetStateNoAddRef(result); + IMFSample *sample; + HRESULT hr = S_OK; + + EnterCriticalSection(&source->cs); + + if (source->state == SOURCE_SHUTDOWN) + hr = MF_E_SHUTDOWN; + else if (source->state == SOURCE_RUNNING && SUCCEEDED(hr = object_queue_pop(&stream->samples, (IUnknown **)&sample))) + media_stream_send_sample(stream, sample, token); + else if (SUCCEEDED(hr = object_queue_push(&stream->tokens, token)) && source->state == SOURCE_RUNNING) + queue_media_source_read(source); + + LeaveCriticalSection(&source->cs); + + return hr; +} + +DEFINE_MF_ASYNC_CALLBACK(media_stream, async_request, IMFMediaStream_iface) + static HRESULT WINAPI media_stream_RequestSample(IMFMediaStream *iface, IUnknown *token) { struct media_stream *stream = media_stream_from_IMFMediaStream(iface); struct media_source *source = media_source_from_IMFMediaSource(stream->source); - IMFSample *sample; HRESULT hr;
TRACE("stream %p, token %p\n", stream, token); @@ -818,10 +839,8 @@ static HRESULT WINAPI media_stream_RequestSample(IMFMediaStream *iface, IUnknown hr = MF_E_MEDIA_SOURCE_WRONGSTATE; else if (stream->eos) hr = MF_E_END_OF_STREAM; - else if (source->state == SOURCE_RUNNING && SUCCEEDED(hr = object_queue_pop(&stream->samples, (IUnknown **)&sample))) - hr = media_stream_send_sample(stream, sample, token); - else if (SUCCEEDED(hr = object_queue_push(&stream->tokens, token))) - queue_media_source_read(source); + else + hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &stream->async_request_iface, token);
LeaveCriticalSection(&source->cs);
@@ -853,6 +872,7 @@ static HRESULT media_stream_create(IMFMediaSource *source, IMFStreamDescriptor * return E_OUTOFMEMORY;
object->IMFMediaStream_iface.lpVtbl = &media_stream_vtbl; + object->async_request_iface.lpVtbl = &media_stream_async_request_vtbl; object->refcount = 1;
if (FAILED(hr = MFCreateEventQueue(&object->queue))) @@ -1247,8 +1267,7 @@ static HRESULT WINAPI media_source_Start(IMFMediaSource *iface, IMFPresentationD hr = MF_E_UNSUPPORTED_TIME_FORMAT; else if (SUCCEEDED(hr = async_start_params_create(descriptor, format, position, &op))) { - if (SUCCEEDED(hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &source->async_start_iface, op))) - source->pending_state++; + hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &source->async_start_iface, op); IUnknown_Release(op); }
@@ -1268,8 +1287,8 @@ static HRESULT WINAPI media_source_Stop(IMFMediaSource *iface)
if (source->state == SOURCE_SHUTDOWN) hr = MF_E_SHUTDOWN; - else if (SUCCEEDED(hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &source->async_stop_iface, NULL))) - source->pending_state++; + else + hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &source->async_stop_iface, NULL);
LeaveCriticalSection(&source->cs);
@@ -1289,8 +1308,8 @@ static HRESULT WINAPI media_source_Pause(IMFMediaSource *iface) hr = MF_E_SHUTDOWN; else if (source->state != SOURCE_RUNNING) hr = MF_E_INVALID_STATE_TRANSITION; - else if (SUCCEEDED(hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &source->async_pause_iface, NULL))) - source->pending_state++; + else + hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &source->async_pause_iface, NULL);
LeaveCriticalSection(&source->cs);
From: Rémi Bernon rbernon@codeweavers.com
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=57204 --- dlls/winedmo/unix_demuxer.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-)
diff --git a/dlls/winedmo/unix_demuxer.c b/dlls/winedmo/unix_demuxer.c index 50be8688397..12fd998e7e4 100644 --- a/dlls/winedmo/unix_demuxer.c +++ b/dlls/winedmo/unix_demuxer.c @@ -91,6 +91,7 @@ NTSTATUS demuxer_create( void *arg ) { struct demuxer_create_params *params = arg; const char *ext = params->url ? strrchr( params->url, '.' ) : ""; + const AVInputFormat *format; AVFormatContext *ctx; int ret;
@@ -110,6 +111,7 @@ NTSTATUS demuxer_create( void *arg ) avformat_free_context( ctx ); return STATUS_UNSUCCESSFUL; } + format = ctx->iformat;
if ((params->duration = get_context_duration( ctx )) == AV_NOPTS_VALUE) { @@ -125,12 +127,12 @@ NTSTATUS demuxer_create( void *arg )
params->demuxer.handle = (UINT_PTR)ctx; params->stream_count = ctx->nb_streams; - if (strstr( ctx->iformat->name, "mp4" )) strcpy( params->mime_type, "video/mp4" ); - else if (strstr( ctx->iformat->name, "avi" )) strcpy( params->mime_type, "video/avi" ); - else if (strstr( ctx->iformat->name, "mpeg" )) strcpy( params->mime_type, "video/mpeg" ); - else if (strstr( ctx->iformat->name, "mp3" )) strcpy( params->mime_type, "audio/mp3" ); - else if (strstr( ctx->iformat->name, "wav" )) strcpy( params->mime_type, "audio/wav" ); - else if (strstr( ctx->iformat->name, "asf" )) + if (strstr( format->name, "mp4" )) strcpy( params->mime_type, "video/mp4" ); + else if (strstr( format->name, "avi" )) strcpy( params->mime_type, "video/avi" ); + else if (strstr( format->name, "mpeg" )) strcpy( params->mime_type, "video/mpeg" ); + else if (strstr( format->name, "mp3" )) strcpy( params->mime_type, "audio/mp3" ); + else if (strstr( format->name, "wav" )) strcpy( params->mime_type, "audio/wav" ); + else if (strstr( format->name, "asf" )) { if (!strcmp( ext, ".wma" )) strcpy( params->mime_type, "audio/x-ms-wma" ); else if (!strcmp( ext, ".wmv" )) strcpy( params->mime_type, "video/x-ms-wmv" ); @@ -138,7 +140,7 @@ NTSTATUS demuxer_create( void *arg ) } else { - FIXME( "Unknown MIME type for format %s, url %s\n", debugstr_a(ctx->iformat->name), debugstr_a(params->url) ); + FIXME( "Unknown MIME type for format %s, url %s\n", debugstr_a(format->name), debugstr_a(params->url) ); strcpy( params->mime_type, "video/x-application" ); }
From: Rémi Bernon rbernon@codeweavers.com
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=57204 --- dlls/winedmo/unix_demuxer.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/dlls/winedmo/unix_demuxer.c b/dlls/winedmo/unix_demuxer.c index 12fd998e7e4..6f3264f05bd 100644 --- a/dlls/winedmo/unix_demuxer.c +++ b/dlls/winedmo/unix_demuxer.c @@ -98,18 +98,12 @@ NTSTATUS demuxer_create( void *arg ) TRACE( "context %p, url %s, mime %s\n", params->context, debugstr_a(params->url), debugstr_a(params->mime_type) );
if (!(ctx = avformat_alloc_context())) return STATUS_NO_MEMORY; - if (!(ctx->pb = avio_alloc_context( NULL, 0, 0, params->context, unix_read_callback, NULL, unix_seek_callback ))) - { - avformat_free_context( ctx ); - return STATUS_NO_MEMORY; - } + if (!(ctx->pb = avio_alloc_context( NULL, 0, 0, params->context, unix_read_callback, NULL, unix_seek_callback ))) goto failed;
if ((ret = avformat_open_input( &ctx, NULL, NULL, NULL )) < 0) { ERR( "Failed to open input, error %s.\n", debugstr_averr(ret) ); - avio_context_free( &ctx->pb ); - avformat_free_context( ctx ); - return STATUS_UNSUCCESSFUL; + goto failed; } format = ctx->iformat;
@@ -117,10 +111,8 @@ NTSTATUS demuxer_create( void *arg ) { if ((ret = avformat_find_stream_info( ctx, NULL )) < 0) { - ERR( "Failed to find stream info, ret %d (%s).\n", ret, av_err2str(ret) ); - avio_context_free( &ctx->pb ); - avformat_free_context( ctx ); - return STATUS_UNSUCCESSFUL; + ERR( "Failed to find stream info, error %s.\n", debugstr_averr(ret) ); + goto failed; } params->duration = get_context_duration( ctx ); } @@ -145,6 +137,14 @@ NTSTATUS demuxer_create( void *arg ) }
return STATUS_SUCCESS; + +failed: + if (ctx) + { + avio_context_free( &ctx->pb ); + avformat_free_context( ctx ); + } + return STATUS_UNSUCCESSFUL; }
NTSTATUS demuxer_destroy( void *arg )
From: Rémi Bernon rbernon@codeweavers.com
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=57204 --- dlls/winedmo/unix_demuxer.c | 90 ++++++++++++++++++++----------------- 1 file changed, 49 insertions(+), 41 deletions(-)
diff --git a/dlls/winedmo/unix_demuxer.c b/dlls/winedmo/unix_demuxer.c index 6f3264f05bd..d40b80da326 100644 --- a/dlls/winedmo/unix_demuxer.c +++ b/dlls/winedmo/unix_demuxer.c @@ -34,9 +34,14 @@ static inline const char *debugstr_averr( int err ) return wine_dbg_sprintf( "%d (%s)", err, av_err2str(err) ); }
-static AVFormatContext *get_demuxer( struct winedmo_demuxer demuxer ) +struct demuxer { - return (AVFormatContext *)(UINT_PTR)demuxer.handle; + AVFormatContext *ctx; +}; + +static struct demuxer *get_demuxer( struct winedmo_demuxer demuxer ) +{ + return (struct demuxer *)(UINT_PTR)demuxer.handle; }
static INT64 get_user_time( INT64 time, AVRational time_base ) @@ -92,33 +97,34 @@ NTSTATUS demuxer_create( void *arg ) struct demuxer_create_params *params = arg; const char *ext = params->url ? strrchr( params->url, '.' ) : ""; const AVInputFormat *format; - AVFormatContext *ctx; + struct demuxer *demuxer; int ret;
TRACE( "context %p, url %s, mime %s\n", params->context, debugstr_a(params->url), debugstr_a(params->mime_type) );
- if (!(ctx = avformat_alloc_context())) return STATUS_NO_MEMORY; - if (!(ctx->pb = avio_alloc_context( NULL, 0, 0, params->context, unix_read_callback, NULL, unix_seek_callback ))) goto failed; + if (!(demuxer = calloc( 1, sizeof(*demuxer) ))) return STATUS_NO_MEMORY; + if (!(demuxer->ctx = avformat_alloc_context())) goto failed; + if (!(demuxer->ctx->pb = avio_alloc_context( NULL, 0, 0, params->context, unix_read_callback, NULL, unix_seek_callback ))) goto failed;
- if ((ret = avformat_open_input( &ctx, NULL, NULL, NULL )) < 0) + if ((ret = avformat_open_input( &demuxer->ctx, NULL, NULL, NULL )) < 0) { ERR( "Failed to open input, error %s.\n", debugstr_averr(ret) ); goto failed; } - format = ctx->iformat; + format = demuxer->ctx->iformat;
- if ((params->duration = get_context_duration( ctx )) == AV_NOPTS_VALUE) + if ((params->duration = get_context_duration( demuxer->ctx )) == AV_NOPTS_VALUE) { - if ((ret = avformat_find_stream_info( ctx, NULL )) < 0) + if ((ret = avformat_find_stream_info( demuxer->ctx, NULL )) < 0) { ERR( "Failed to find stream info, error %s.\n", debugstr_averr(ret) ); goto failed; } - params->duration = get_context_duration( ctx ); + params->duration = get_context_duration( demuxer->ctx ); }
- params->demuxer.handle = (UINT_PTR)ctx; - params->stream_count = ctx->nb_streams; + params->demuxer.handle = (UINT_PTR)demuxer; + params->stream_count = demuxer->ctx->nb_streams; if (strstr( format->name, "mp4" )) strcpy( params->mime_type, "video/mp4" ); else if (strstr( format->name, "avi" )) strcpy( params->mime_type, "video/avi" ); else if (strstr( format->name, "mpeg" )) strcpy( params->mime_type, "video/mpeg" ); @@ -139,24 +145,26 @@ NTSTATUS demuxer_create( void *arg ) return STATUS_SUCCESS;
failed: - if (ctx) + if (demuxer->ctx) { - avio_context_free( &ctx->pb ); - avformat_free_context( ctx ); + avio_context_free( &demuxer->ctx->pb ); + avformat_free_context( demuxer->ctx ); } + free( demuxer ); return STATUS_UNSUCCESSFUL; }
NTSTATUS demuxer_destroy( void *arg ) { struct demuxer_destroy_params *params = arg; - AVFormatContext *ctx = get_demuxer( params->demuxer ); + struct demuxer *demuxer = get_demuxer( params->demuxer );
- TRACE( "context %p\n", ctx ); + TRACE( "demuxer %p\n", demuxer );
- params->context = ctx->pb->opaque; - avio_context_free( &ctx->pb ); - avformat_free_context( ctx ); + params->context = demuxer->ctx->pb->opaque; + avio_context_free( &demuxer->ctx->pb ); + avformat_free_context( demuxer->ctx ); + free( demuxer );
return STATUS_SUCCESS; } @@ -164,21 +172,21 @@ NTSTATUS demuxer_destroy( void *arg ) NTSTATUS demuxer_read( void *arg ) { struct demuxer_read_params *params = arg; - AVFormatContext *ctx = get_demuxer( params->demuxer ); + struct demuxer *demuxer = get_demuxer( params->demuxer ); struct sample *sample = ¶ms->sample; UINT capacity = params->sample.size; AVStream *stream; AVPacket *packet; int ret;
- TRACE( "context %p, capacity %#x\n", ctx, capacity ); + TRACE( "demuxer %p, capacity %#x\n", demuxer, capacity );
- if (!(packet = ctx->opaque)) + if (!(packet = demuxer->ctx->opaque)) { if (!(packet = av_packet_alloc())) return STATUS_NO_MEMORY; - if ((ret = av_read_frame( ctx, packet )) < 0) + if ((ret = av_read_frame( demuxer->ctx, packet )) < 0) { - TRACE( "Failed to read context %p, error %s.\n", ctx, debugstr_averr( ret ) ); + TRACE( "Failed to read demuxer %p, error %s.\n", demuxer, debugstr_averr( ret ) ); av_packet_free( &packet ); if (ret == AVERROR_EOF) return STATUS_END_OF_FILE; return STATUS_UNSUCCESSFUL; @@ -188,11 +196,11 @@ NTSTATUS demuxer_read( void *arg ) params->sample.size = packet->size; if ((capacity < packet->size)) { - ctx->opaque = packet; + demuxer->ctx->opaque = packet; return STATUS_BUFFER_TOO_SMALL; }
- stream = ctx->streams[packet->stream_index]; + stream = demuxer->ctx->streams[packet->stream_index]; sample->pts = get_stream_time( stream, packet->pts ); sample->dts = get_stream_time( stream, packet->dts ); sample->duration = get_stream_time( stream, packet->duration ); @@ -200,7 +208,7 @@ NTSTATUS demuxer_read( void *arg ) memcpy( (void *)(UINT_PTR)sample->data, packet->data, packet->size ); params->stream = packet->stream_index; av_packet_free( &packet ); - ctx->opaque = NULL; + demuxer->ctx->opaque = NULL;
return STATUS_SUCCESS; } @@ -208,15 +216,15 @@ NTSTATUS demuxer_read( void *arg ) NTSTATUS demuxer_seek( void *arg ) { struct demuxer_seek_params *params = arg; - AVFormatContext *ctx = get_demuxer( params->demuxer ); + struct demuxer *demuxer = get_demuxer( params->demuxer ); int64_t timestamp = params->timestamp * AV_TIME_BASE / 10000000; int ret;
- TRACE( "context %p, timestamp 0x%s\n", ctx, wine_dbgstr_longlong( params->timestamp ) ); + TRACE( "demuxer %p, timestamp 0x%s\n", demuxer, wine_dbgstr_longlong( params->timestamp ) );
- if ((ret = av_seek_frame( ctx, -1, timestamp, AVSEEK_FLAG_ANY )) < 0) + if ((ret = av_seek_frame( demuxer->ctx, -1, timestamp, AVSEEK_FLAG_ANY )) < 0) { - ERR( "Failed to seek context %p, error %s.\n", ctx, debugstr_averr(ret) ); + ERR( "Failed to seek demuxer %p, error %s.\n", demuxer, debugstr_averr(ret) ); return STATUS_UNSUCCESSFUL; }
@@ -226,11 +234,11 @@ NTSTATUS demuxer_seek( void *arg ) NTSTATUS demuxer_stream_lang( void *arg ) { struct demuxer_stream_lang_params *params = arg; - AVFormatContext *ctx = get_demuxer( params->demuxer ); - AVStream *stream = ctx->streams[params->stream]; + struct demuxer *demuxer = get_demuxer( params->demuxer ); + AVStream *stream = demuxer->ctx->streams[params->stream]; AVDictionaryEntry *tag;
- TRACE( "context %p, stream %u\n", ctx, params->stream ); + TRACE( "demuxer %p, stream %u\n", demuxer, params->stream );
if (!(tag = av_dict_get( stream->metadata, "language", NULL, AV_DICT_IGNORE_SUFFIX ))) return STATUS_NOT_FOUND; @@ -242,11 +250,11 @@ NTSTATUS demuxer_stream_lang( void *arg ) NTSTATUS demuxer_stream_name( void *arg ) { struct demuxer_stream_name_params *params = arg; - AVFormatContext *ctx = get_demuxer( params->demuxer ); - AVStream *stream = ctx->streams[params->stream]; + struct demuxer *demuxer = get_demuxer( params->demuxer ); + AVStream *stream = demuxer->ctx->streams[params->stream]; AVDictionaryEntry *tag;
- TRACE( "context %p, stream %u\n", ctx, params->stream ); + TRACE( "demuxer %p, stream %u\n", demuxer, params->stream );
if (!(tag = av_dict_get( stream->metadata, "title", NULL, AV_DICT_IGNORE_SUFFIX ))) return STATUS_NOT_FOUND; @@ -258,10 +266,10 @@ NTSTATUS demuxer_stream_name( void *arg ) NTSTATUS demuxer_stream_type( void *arg ) { struct demuxer_stream_type_params *params = arg; - AVFormatContext *ctx = get_demuxer( params->demuxer ); - AVStream *stream = ctx->streams[params->stream]; + struct demuxer *demuxer = get_demuxer( params->demuxer ); + AVStream *stream = demuxer->ctx->streams[params->stream];
- TRACE( "context %p, stream %u, stream %p, index %u\n", ctx, params->stream, stream, stream->index ); + TRACE( "demuxer %p, stream %u, stream %p, index %u\n", demuxer, params->stream, stream, stream->index );
return media_type_from_codec_params( stream->codecpar, &stream->sample_aspect_ratio, &stream->avg_frame_rate, 0, ¶ms->media_type );
From: Rémi Bernon rbernon@codeweavers.com
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=57204 --- dlls/winedmo/unix_demuxer.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/dlls/winedmo/unix_demuxer.c b/dlls/winedmo/unix_demuxer.c index d40b80da326..23fc9f7993b 100644 --- a/dlls/winedmo/unix_demuxer.c +++ b/dlls/winedmo/unix_demuxer.c @@ -37,6 +37,8 @@ static inline const char *debugstr_averr( int err ) struct demuxer { AVFormatContext *ctx; + + AVPacket *last_packet; /* last read packet */ };
static struct demuxer *get_demuxer( struct winedmo_demuxer demuxer ) @@ -181,7 +183,7 @@ NTSTATUS demuxer_read( void *arg )
TRACE( "demuxer %p, capacity %#x\n", demuxer, capacity );
- if (!(packet = demuxer->ctx->opaque)) + if (!(packet = demuxer->last_packet)) { if (!(packet = av_packet_alloc())) return STATUS_NO_MEMORY; if ((ret = av_read_frame( demuxer->ctx, packet )) < 0) @@ -196,7 +198,7 @@ NTSTATUS demuxer_read( void *arg ) params->sample.size = packet->size; if ((capacity < packet->size)) { - demuxer->ctx->opaque = packet; + demuxer->last_packet = packet; return STATUS_BUFFER_TOO_SMALL; }
@@ -208,7 +210,7 @@ NTSTATUS demuxer_read( void *arg ) memcpy( (void *)(UINT_PTR)sample->data, packet->data, packet->size ); params->stream = packet->stream_index; av_packet_free( &packet ); - demuxer->ctx->opaque = NULL; + demuxer->last_packet = NULL;
return STATUS_SUCCESS; }
From: Rémi Bernon rbernon@codeweavers.com
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=57204 --- dlls/winedmo/unix_demuxer.c | 36 ++++++++++++++++++++++++++++++++++-- dlls/winedmo/unix_private.h | 1 + 2 files changed, 35 insertions(+), 2 deletions(-)
diff --git a/dlls/winedmo/unix_demuxer.c b/dlls/winedmo/unix_demuxer.c index 23fc9f7993b..3da4a495c95 100644 --- a/dlls/winedmo/unix_demuxer.c +++ b/dlls/winedmo/unix_demuxer.c @@ -34,9 +34,15 @@ static inline const char *debugstr_averr( int err ) return wine_dbg_sprintf( "%d (%s)", err, av_err2str(err) ); }
+struct stream +{ + AVBSFContext *filter; +}; + struct demuxer { AVFormatContext *ctx; + struct stream *streams;
AVPacket *last_packet; /* last read packet */ }; @@ -94,13 +100,29 @@ NTSTATUS demuxer_check( void *arg ) return format ? STATUS_SUCCESS : STATUS_NOT_SUPPORTED; }
+static NTSTATUS demuxer_create_streams( struct demuxer *demuxer ) +{ + UINT i; + + for (i = 0; i < demuxer->ctx->nb_streams; i++) + { + struct stream *stream = demuxer->streams + i; + + av_bsf_get_null_filter( &stream->filter ); + avcodec_parameters_copy( stream->filter->par_in, demuxer->ctx->streams[i]->codecpar ); + avcodec_parameters_copy( stream->filter->par_out, demuxer->ctx->streams[i]->codecpar ); + } + + return STATUS_SUCCESS; +} + NTSTATUS demuxer_create( void *arg ) { struct demuxer_create_params *params = arg; const char *ext = params->url ? strrchr( params->url, '.' ) : ""; const AVInputFormat *format; struct demuxer *demuxer; - int ret; + int i, ret;
TRACE( "context %p, url %s, mime %s\n", params->context, debugstr_a(params->url), debugstr_a(params->mime_type) );
@@ -124,6 +146,8 @@ NTSTATUS demuxer_create( void *arg ) } params->duration = get_context_duration( demuxer->ctx ); } + if (!(demuxer->streams = calloc( demuxer->ctx->nb_streams, sizeof(*demuxer->streams) ))) goto failed; + if (demuxer_create_streams( demuxer )) goto failed;
params->demuxer.handle = (UINT_PTR)demuxer; params->stream_count = demuxer->ctx->nb_streams; @@ -152,6 +176,9 @@ failed: avio_context_free( &demuxer->ctx->pb ); avformat_free_context( demuxer->ctx ); } + for (i = 0; demuxer->streams && i < demuxer->ctx->nb_streams; i++) + av_bsf_free( &demuxer->streams[i].filter ); + free( demuxer->streams ); free( demuxer ); return STATUS_UNSUCCESSFUL; } @@ -160,12 +187,16 @@ NTSTATUS demuxer_destroy( void *arg ) { struct demuxer_destroy_params *params = arg; struct demuxer *demuxer = get_demuxer( params->demuxer ); + int i;
TRACE( "demuxer %p\n", demuxer );
params->context = demuxer->ctx->pb->opaque; avio_context_free( &demuxer->ctx->pb ); avformat_free_context( demuxer->ctx ); + for (i = 0; i < demuxer->ctx->nb_streams; i++) + av_bsf_free( &demuxer->streams[i].filter ); + free( demuxer->streams ); free( demuxer );
return STATUS_SUCCESS; @@ -270,10 +301,11 @@ NTSTATUS demuxer_stream_type( void *arg ) struct demuxer_stream_type_params *params = arg; struct demuxer *demuxer = get_demuxer( params->demuxer ); AVStream *stream = demuxer->ctx->streams[params->stream]; + AVCodecParameters *par = demuxer->streams[params->stream].filter->par_out;
TRACE( "demuxer %p, stream %u, stream %p, index %u\n", demuxer, params->stream, stream, stream->index );
- return media_type_from_codec_params( stream->codecpar, &stream->sample_aspect_ratio, + return media_type_from_codec_params( par, &stream->sample_aspect_ratio, &stream->avg_frame_rate, 0, ¶ms->media_type ); }
diff --git a/dlls/winedmo/unix_private.h b/dlls/winedmo/unix_private.h index bc45f2c6db2..9950077cb33 100644 --- a/dlls/winedmo/unix_private.h +++ b/dlls/winedmo/unix_private.h @@ -27,6 +27,7 @@ #include <libavutil/imgutils.h> #include <libavformat/avformat.h> #include <libavcodec/avcodec.h> +#include <libavcodec/bsf.h> #else typedef struct AVCodecParameters AVCodecParameters; typedef struct AVRational AVRational;
From: Rémi Bernon rbernon@codeweavers.com
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=57204 --- dlls/winedmo/unix_demuxer.c | 74 ++++++++++++++++++++++++++++++------- 1 file changed, 61 insertions(+), 13 deletions(-)
diff --git a/dlls/winedmo/unix_demuxer.c b/dlls/winedmo/unix_demuxer.c index 3da4a495c95..d7fdaffbe6b 100644 --- a/dlls/winedmo/unix_demuxer.c +++ b/dlls/winedmo/unix_demuxer.c @@ -37,6 +37,7 @@ static inline const char *debugstr_averr( int err ) struct stream { AVBSFContext *filter; + BOOL eos; };
struct demuxer @@ -45,6 +46,7 @@ struct demuxer struct stream *streams;
AVPacket *last_packet; /* last read packet */ + struct stream *last_stream; /* last read packet stream */ };
static struct demuxer *get_demuxer( struct winedmo_demuxer demuxer ) @@ -202,6 +204,54 @@ NTSTATUS demuxer_destroy( void *arg ) return STATUS_SUCCESS; }
+static NTSTATUS demuxer_filter_packet( struct demuxer *demuxer, AVPacket **packet ) +{ + struct stream *stream; + int i, ret; + + do + { + if ((*packet = demuxer->last_packet)) return STATUS_SUCCESS; + if (!(*packet = av_packet_alloc())) return STATUS_NO_MEMORY; + + if (!(stream = demuxer->last_stream)) ret = 0; + else + { + if (!(ret = av_bsf_receive_packet( stream->filter, *packet ))) return STATUS_SUCCESS; + if (ret == AVERROR_EOF) stream->eos = TRUE; + if (!ret || ret == AVERROR_EOF || ret == AVERROR(EAGAIN)) ret = 0; + else WARN( "Failed to read packet from filter, error %s.\n", debugstr_averr( ret ) ); + stream = demuxer->last_stream = NULL; + } + + if (!ret && !(ret = av_read_frame( demuxer->ctx, *packet ))) + { + stream = demuxer->streams + (*packet)->stream_index; + ret = av_bsf_send_packet( stream->filter, (*packet) ); + if (ret < 0) WARN( "Failed to send packet to filter, error %s.\n", debugstr_averr( ret ) ); + else demuxer->last_stream = stream; + } + av_packet_free( packet ); + + if (ret == AVERROR_EOF) + { + for (i = 0; ret == AVERROR_EOF && i < demuxer->ctx->nb_streams; i++) + { + if (demuxer->streams[i].eos) continue; + stream = demuxer->streams + i; + ret = av_bsf_send_packet( stream->filter, NULL ); + if (ret < 0) WARN( "Failed to send packet to filter, error %s.\n", debugstr_averr( ret ) ); + else demuxer->last_stream = stream; + } + + if (ret == AVERROR_EOF) return STATUS_END_OF_FILE; + } + } while (!ret || ret == AVERROR(EAGAIN)); + + ERR( "Failed to read packet from demuxer %p, error %s.\n", demuxer, debugstr_averr( ret ) ); + return STATUS_UNSUCCESSFUL; +} + NTSTATUS demuxer_read( void *arg ) { struct demuxer_read_params *params = arg; @@ -210,21 +260,11 @@ NTSTATUS demuxer_read( void *arg ) UINT capacity = params->sample.size; AVStream *stream; AVPacket *packet; - int ret; + NTSTATUS status;
TRACE( "demuxer %p, capacity %#x\n", demuxer, capacity );
- if (!(packet = demuxer->last_packet)) - { - if (!(packet = av_packet_alloc())) return STATUS_NO_MEMORY; - if ((ret = av_read_frame( demuxer->ctx, packet )) < 0) - { - TRACE( "Failed to read demuxer %p, error %s.\n", demuxer, debugstr_averr( ret ) ); - av_packet_free( &packet ); - if (ret == AVERROR_EOF) return STATUS_END_OF_FILE; - return STATUS_UNSUCCESSFUL; - } - } + if ((status = demuxer_filter_packet( demuxer, &packet ))) return status;
params->sample.size = packet->size; if ((capacity < packet->size)) @@ -251,7 +291,7 @@ NTSTATUS demuxer_seek( void *arg ) struct demuxer_seek_params *params = arg; struct demuxer *demuxer = get_demuxer( params->demuxer ); int64_t timestamp = params->timestamp * AV_TIME_BASE / 10000000; - int ret; + int i, ret;
TRACE( "demuxer %p, timestamp 0x%s\n", demuxer, wine_dbgstr_longlong( params->timestamp ) );
@@ -261,6 +301,14 @@ NTSTATUS demuxer_seek( void *arg ) return STATUS_UNSUCCESSFUL; }
+ for (i = 0; i < demuxer->ctx->nb_streams; i++) + { + av_bsf_flush( demuxer->streams[i].filter ); + demuxer->streams[i].eos = FALSE; + } + av_packet_free( &demuxer->last_packet ); + demuxer->last_stream = NULL; + return STATUS_SUCCESS; }
From: Rémi Bernon rbernon@codeweavers.com
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=57204 --- dlls/winedmo/unix_demuxer.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
diff --git a/dlls/winedmo/unix_demuxer.c b/dlls/winedmo/unix_demuxer.c index d7fdaffbe6b..15d906e0c5f 100644 --- a/dlls/winedmo/unix_demuxer.c +++ b/dlls/winedmo/unix_demuxer.c @@ -108,7 +108,22 @@ static NTSTATUS demuxer_create_streams( struct demuxer *demuxer )
for (i = 0; i < demuxer->ctx->nb_streams; i++) { + AVCodecParameters *par = demuxer->ctx->streams[i]->codecpar; struct stream *stream = demuxer->streams + i; + const AVBitStreamFilter *filter; + + if (par->codec_id == AV_CODEC_ID_H264) + { + if (!(filter = av_bsf_get_by_name( "h264_mp4toannexb" ))) + ERR( "Failed to find H264 bitstream filter\n" ); + else + { + if (av_bsf_alloc( filter, &stream->filter ) < 0) return STATUS_UNSUCCESSFUL; + avcodec_parameters_copy( stream->filter->par_in, par ); + av_bsf_init( stream->filter ); + continue; + } + }
av_bsf_get_null_filter( &stream->filter ); avcodec_parameters_copy( stream->filter->par_in, demuxer->ctx->streams[i]->codecpar );