[PATCH v2 0/8] MR6551: winedmo: Convert H264 streams to Annex B format.
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. https://gitlab.winehq.org/wine/wine/-/merge_requests/6551
From: Rémi Bernon <rbernon(a)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); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/6551
From: Rémi Bernon <rbernon(a)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" ); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/6551
From: Rémi Bernon <rbernon(a)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 ) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/6551
From: Rémi Bernon <rbernon(a)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 ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/6551
From: Rémi Bernon <rbernon(a)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; } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/6551
From: Rémi Bernon <rbernon(a)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; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/6551
From: Rémi Bernon <rbernon(a)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; } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/6551
From: Rémi Bernon <rbernon(a)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 ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/6551
participants (1)
-
Rémi Bernon