Commit a2bc9e15 authored by Romain Vimont's avatar Romain Vimont Committed by Thomas Guillem

decoder: remove input thread and ES dependency

As suggested by Rémi:

> the decoder should use opaque callbacks provided by the ES out rather
> than "see" the input and the ES.

<https://mailman.videolan.org/pipermail/vlc-devel/2019-May/125088.html>
parent e78831df
......@@ -45,10 +45,8 @@
#include "audio_output/aout_internal.h"
#include "stream_output/stream_output.h"
#include "input_internal.h"
#include "../clock/clock.h"
#include "decoder.h"
#include "event.h"
#include "resource.h"
#include "../video_output/vout_internal.h"
......@@ -66,11 +64,12 @@ enum reload
struct decoder_owner
{
decoder_t dec;
input_thread_t *p_input;
vlc_es_id_t *id;
input_resource_t*p_resource;
vlc_clock_t *p_clock;
const struct input_decoder_callbacks *cbs;
void *cbs_userdata;
ssize_t i_spu_channel;
int64_t i_spu_order;
......@@ -156,6 +155,11 @@ struct decoder_owner
#define DECODER_SPU_VOUT_WAIT_DURATION VLC_TICK_FROM_MS(200)
#define BLOCK_FLAG_CORE_PRIVATE_RELOADED (1 << BLOCK_FLAG_CORE_PRIVATE_SHIFT)
#define decoder_Notify(decoder_priv, event, ...) \
if (decoder_priv->cbs && decoder_priv->cbs->event) \
decoder_priv->cbs->event(&decoder_priv->dec, __VA_ARGS__, \
decoder_priv->cbs_userdata);
static inline struct decoder_owner *dec_get_owner( decoder_t *p_dec )
{
return container_of( p_dec, struct decoder_owner, dec );
......@@ -542,13 +546,8 @@ static int vout_update_format( decoder_t *p_dec )
.dpb_size = dpb_size + p_dec->i_extra_picture_buffers + 1,
.mouse_event = MouseEvent, .mouse_opaque = p_dec
} );
if (p_vout && p_owner->p_input)
input_SendEventVout(p_owner->p_input,
&(struct vlc_input_event_vout) {
.action = VLC_INPUT_EVENT_VOUT_ADDED,
.vout = p_vout,
.id = p_owner->id,
});
if (p_vout)
decoder_Notify(p_owner, on_vout_added, p_vout);
vlc_mutex_lock( &p_owner->lock );
p_owner->p_vout = p_vout;
......@@ -664,12 +663,11 @@ static int DecoderGetInputAttachments( decoder_t *p_dec,
int *pi_attachment )
{
struct decoder_owner *p_owner = dec_get_owner( p_dec );
input_thread_t *p_input = p_owner->p_input;
if( unlikely(p_input == NULL) )
if (!p_owner->cbs || !p_owner->cbs->get_attachments)
return VLC_ENOOBJ;
int ret = input_GetAttachments( p_input, ppp_attachment );
int ret = p_owner->cbs->get_attachments(p_dec, ppp_attachment,
p_owner->cbs_userdata);
if (ret < 0)
return VLC_EGENERIC;
*pi_attachment = ret;
......@@ -1059,13 +1057,8 @@ discard:
static void DecoderUpdateStatVideo( struct decoder_owner *p_owner,
unsigned decoded, unsigned lost )
{
input_thread_t *p_input = p_owner->p_input;
unsigned displayed = 0;
/* Update ugly stat */
if( p_input == NULL )
return;
if( p_owner->p_vout != NULL )
{
unsigned vout_lost = 0;
......@@ -1074,17 +1067,7 @@ static void DecoderUpdateStatVideo( struct decoder_owner *p_owner,
lost += vout_lost;
}
struct input_stats *stats = input_priv(p_input)->stats;
if( stats != NULL )
{
atomic_fetch_add_explicit(&stats->decoded_video, decoded,
memory_order_relaxed);
atomic_fetch_add_explicit(&stats->lost_pictures, lost,
memory_order_relaxed);
atomic_fetch_add_explicit(&stats->displayed_pictures, displayed,
memory_order_relaxed);
}
decoder_Notify(p_owner, on_new_video_stats, decoded, lost, displayed);
}
static void DecoderQueueVideo( decoder_t *p_dec, picture_t *p_pic )
......@@ -1119,11 +1102,7 @@ static void DecoderQueueThumbnail( decoder_t *p_dec, picture_t *p_pic )
struct decoder_owner *p_owner = dec_get_owner( p_dec );
if( p_owner->b_first )
{
assert(p_owner->p_input);
input_SendEvent(p_owner->p_input, &(struct vlc_input_event) {
.type = INPUT_EVENT_THUMBNAIL_READY,
.thumbnail = p_pic
});
decoder_Notify(p_owner, on_thumbnail_ready, p_pic);
p_owner->b_first = false;
}
picture_Release( p_pic );
......@@ -1209,13 +1188,8 @@ static void DecoderPlayAudio( decoder_t *p_dec, block_t *p_audio,
static void DecoderUpdateStatAudio( struct decoder_owner *p_owner,
unsigned decoded, unsigned lost )
{
input_thread_t *p_input = p_owner->p_input;
unsigned played = 0;
/* Update ugly stat */
if( p_input == NULL )
return;
if( p_owner->p_aout != NULL )
{
unsigned aout_lost;
......@@ -1224,17 +1198,7 @@ static void DecoderUpdateStatAudio( struct decoder_owner *p_owner,
lost += aout_lost;
}
struct input_stats *stats = input_priv(p_input)->stats;
if( stats != NULL )
{
atomic_fetch_add_explicit(&stats->lost_abuffers, lost,
memory_order_relaxed);
atomic_fetch_add_explicit(&stats->played_abuffers, played,
memory_order_relaxed);
atomic_fetch_add_explicit(&stats->decoded_audio, decoded,
memory_order_relaxed);
}
decoder_Notify(p_owner, on_new_audio_stats, decoded, lost, played);
}
static void DecoderQueueAudio( decoder_t *p_dec, block_t *p_aout_buf )
......@@ -1782,10 +1746,11 @@ static const struct decoder_owner_callbacks dec_spu_cbs =
* \return the decoder object
*/
static decoder_t * CreateDecoder( vlc_object_t *p_parent,
input_thread_t *p_input, vlc_es_id_t *id,
const es_format_t *fmt, vlc_clock_t *p_clock,
input_resource_t *p_resource,
sout_instance_t *p_sout )
sout_instance_t *p_sout, bool b_thumbnailing,
const struct input_decoder_callbacks *cbs,
void *cbs_userdata )
{
decoder_t *p_dec;
struct decoder_owner *p_owner;
......@@ -1795,11 +1760,11 @@ static decoder_t * CreateDecoder( vlc_object_t *p_parent,
return NULL;
p_dec = &p_owner->dec;
p_owner->id = id;
p_owner->p_clock = p_clock;
p_owner->i_preroll_end = (vlc_tick_t)INT64_MIN;
p_owner->p_input = p_input;
p_owner->p_resource = p_resource;
p_owner->cbs = cbs;
p_owner->cbs_userdata = cbs_userdata;
p_owner->p_aout = NULL;
p_owner->p_vout = NULL;
p_owner->i_spu_channel = -1;
......@@ -1872,7 +1837,7 @@ static decoder_t * CreateDecoder( vlc_object_t *p_parent,
switch( fmt->i_cat )
{
case VIDEO_ES:
if( !p_input || !input_priv( p_input )->b_thumbnailing )
if( !b_thumbnailing )
p_dec->cbs = &dec_video_cbs;
else
p_dec->cbs = &dec_thumbnailer_cbs;
......@@ -1974,13 +1939,7 @@ static void DeleteDecoder( decoder_t * p_dec )
/* Reset the cancel state that was set before joining the decoder
* thread */
vout_Cancel(vout, false);
if (p_owner->p_input)
input_SendEventVout(p_owner->p_input,
&(struct vlc_input_event_vout) {
.action = VLC_INPUT_EVENT_VOUT_DELETED,
.vout = vout,
.id = p_owner->id,
});
decoder_Notify(p_owner, on_vout_deleted, vout);
input_resource_PutVout(p_owner->p_resource, vout);
}
break;
......@@ -2038,17 +1997,19 @@ static void DecoderUnsupportedCodec( decoder_t *p_dec, const es_format_t *fmt, b
}
/* TODO: pass p_sout through p_resource? -- Courmisch */
static decoder_t *decoder_New( vlc_object_t *p_parent, input_thread_t *p_input,
vlc_es_id_t *id, const es_format_t *fmt,
static decoder_t *decoder_New( vlc_object_t *p_parent, const es_format_t *fmt,
vlc_clock_t *p_clock, input_resource_t *p_resource,
sout_instance_t *p_sout )
sout_instance_t *p_sout, bool thumbnailing,
const struct input_decoder_callbacks *cbs,
void *userdata)
{
decoder_t *p_dec = NULL;
const char *psz_type = p_sout ? N_("packetizer") : N_("decoder");
int i_priority;
/* Create the decoder configuration structure */
p_dec = CreateDecoder( p_parent, p_input, id, fmt, p_clock, p_resource, p_sout );
p_dec = CreateDecoder( p_parent, fmt, p_clock, p_resource, p_sout,
thumbnailing, cbs, userdata );
if( p_dec == NULL )
{
msg_Err( p_parent, "could not create %s", psz_type );
......@@ -2107,13 +2068,14 @@ static decoder_t *decoder_New( vlc_object_t *p_parent, input_thread_t *p_input,
* \param p_es the es descriptor
* \return the spawned decoder object
*/
decoder_t *input_DecoderNew( input_thread_t *p_input, vlc_es_id_t *id,
es_format_t *fmt, vlc_clock_t *p_clock,
sout_instance_t *p_sout )
decoder_t *input_DecoderNew( vlc_object_t *parent, es_format_t *fmt,
vlc_clock_t *p_clock, input_resource_t *resource,
sout_instance_t *p_sout, bool thumbnailing,
const struct input_decoder_callbacks *cbs,
void *cbs_userdata)
{
assert(p_input && id);
return decoder_New( VLC_OBJECT(p_input), p_input, id, fmt, p_clock,
input_priv(p_input)->p_resource, p_sout );
return decoder_New( parent, fmt, p_clock, resource, p_sout, thumbnailing,
cbs, cbs_userdata );
}
/**
......@@ -2122,7 +2084,8 @@ decoder_t *input_DecoderNew( input_thread_t *p_input, vlc_es_id_t *id,
decoder_t *input_DecoderCreate( vlc_object_t *p_parent, const es_format_t *fmt,
input_resource_t *p_resource )
{
return decoder_New( p_parent, NULL, NULL, fmt, NULL, p_resource, NULL );
return decoder_New( p_parent, fmt, NULL, p_resource, NULL, false, NULL,
NULL );
}
......@@ -2342,8 +2305,9 @@ int input_DecoderSetCcState( decoder_t *p_dec, vlc_fourcc_t codec,
es_format_Init( &fmt, SPU_ES, codec );
fmt.subs.cc.i_channel = i_channel;
fmt.subs.cc.i_reorder_depth = p_owner->cc.desc.i_reorder_depth;
p_cc = input_DecoderNew( p_owner->p_input, p_owner->id, &fmt,
p_owner->p_clock, p_owner->p_sout );
p_cc = input_DecoderNew( VLC_OBJECT(p_dec), &fmt, p_owner->p_clock,
p_owner->p_resource, p_owner->p_sout, false,
NULL, NULL );
if( !p_cc )
{
msg_Err( p_dec, "could not create decoder" );
......
......@@ -28,8 +28,32 @@
#include <vlc_codec.h>
#include <vlc_mouse.h>
decoder_t *input_DecoderNew( input_thread_t *, vlc_es_id_t *, es_format_t *,
vlc_clock_t *, sout_instance_t * ) VLC_USED;
struct input_decoder_callbacks {
/* notifications */
void (*on_vout_added)(decoder_t *decoder, vout_thread_t *vout,
void *userdata);
void (*on_vout_deleted)(decoder_t *decoder, vout_thread_t *vout,
void *userdata);
void (*on_thumbnail_ready)(decoder_t *decoder, picture_t *pic,
void *userdata);
void (*on_new_video_stats)(decoder_t *decoder, unsigned decoded,
unsigned lost, unsigned displayed,
void *userdata);
void (*on_new_audio_stats)(decoder_t *decoder, unsigned decoded,
unsigned lost, unsigned played, void *userdata);
/* requests */
int (*get_attachments)(decoder_t *decoder,
input_attachment_t ***ppp_attachment,
void *userdata);
};
decoder_t *input_DecoderNew( vlc_object_t *parent, es_format_t *, vlc_clock_t *,
input_resource_t *, sout_instance_t *,
bool thumbnailing,
const struct input_decoder_callbacks *cbs,
void *userdata ) VLC_USED;
/**
* This function changes the pause state.
......
......@@ -259,6 +259,138 @@ static inline int EsOutGetClosedCaptionsChannel( const es_format_t *p_fmt )
for( int fetes_i=0; fetes_i<2; fetes_i++ ) \
vlc_list_foreach( pos, (!fetes_i ? &p_sys->es : &p_sys->es_slaves), node )
static vlc_es_id_t *
FindEsIdFromDecoder(es_out_sys_t *p_sys, decoder_t *decoder)
{
es_out_id_t *es;
foreach_es_then_es_slaves(es)
if (es->p_dec == decoder)
return &es->id;
return NULL;
}
static void
decoder_on_vout_added(decoder_t *decoder, vout_thread_t *vout, void *userdata)
{
es_out_sys_t *priv = userdata;
if (!priv->p_input)
return;
vlc_es_id_t *id = FindEsIdFromDecoder(priv, decoder);
assert(id);
struct vlc_input_event_vout event = {
.action = VLC_INPUT_EVENT_VOUT_ADDED,
.vout = vout,
.id = id,
};
input_SendEventVout(priv->p_input, &event);
}
static void
decoder_on_vout_deleted(decoder_t *decoder, vout_thread_t *vout, void *userdata)
{
es_out_sys_t *priv = userdata;
if (!priv->p_input)
return;
vlc_es_id_t *id = FindEsIdFromDecoder(priv, decoder);
assert(id);
struct vlc_input_event_vout event = {
.action = VLC_INPUT_EVENT_VOUT_DELETED,
.vout = vout,
.id = id,
};
input_SendEventVout(priv->p_input, &event);
}
static void
decoder_on_thumbnail_ready(decoder_t *decoder, picture_t *pic, void *userdata)
{
es_out_sys_t *priv = userdata;
if (!priv->p_input)
return;
vlc_es_id_t *id = FindEsIdFromDecoder(priv, decoder);
assert(id);
struct vlc_input_event event = {
.type = INPUT_EVENT_THUMBNAIL_READY,
.thumbnail = pic,
};
input_SendEvent(priv->p_input, &event);
}
static void
decoder_on_new_video_stats(decoder_t *decoder, unsigned decoded, unsigned lost,
unsigned displayed, void *userdata)
{
(void) decoder;
es_out_sys_t *priv = userdata;
if (!priv->p_input)
return;
struct input_stats *stats = input_priv(priv->p_input)->stats;
if (!stats)
return;
atomic_fetch_add_explicit(&stats->decoded_video, decoded,
memory_order_relaxed);
atomic_fetch_add_explicit(&stats->lost_pictures, lost,
memory_order_relaxed);
atomic_fetch_add_explicit(&stats->displayed_pictures, displayed,
memory_order_relaxed);
}
static void
decoder_on_new_audio_stats(decoder_t *decoder, unsigned decoded, unsigned lost,
unsigned played, void *userdata)
{
(void) decoder;
es_out_sys_t *priv = userdata;
if (!priv->p_input)
return;
struct input_stats *stats = input_priv(priv->p_input)->stats;
if (!stats)
return;
atomic_fetch_add_explicit(&stats->decoded_audio, decoded,
memory_order_relaxed);
atomic_fetch_add_explicit(&stats->lost_abuffers, lost,
memory_order_relaxed);
atomic_fetch_add_explicit(&stats->played_abuffers, played,
memory_order_relaxed);
}
static int
decoder_get_attachments(decoder_t *decoder,
input_attachment_t ***ppp_attachment,
void *userdata)
{
(void) decoder;
es_out_sys_t *priv = userdata;
if (!priv->p_input)
return -1;
return input_GetAttachments(priv->p_input, ppp_attachment);
}
static const struct input_decoder_callbacks decoder_cbs = {
.on_vout_added = decoder_on_vout_added,
.on_vout_deleted = decoder_on_vout_deleted,
.on_thumbnail_ready = decoder_on_thumbnail_ready,
.on_new_video_stats = decoder_on_new_video_stats,
.on_new_audio_stats = decoder_on_new_audio_stats,
.get_attachments = decoder_get_attachments,
};
/*****************************************************************************
* Es category specific structs
......@@ -640,8 +772,12 @@ static int EsOutSetRecord( es_out_t *out, bool b_record )
if( !p_es->p_dec )
continue;
p_es->p_dec_record = input_DecoderNew( p_input, &p_es->id, &p_es->fmt,
NULL, p_sys->p_sout_record );
p_es->p_dec_record =
input_DecoderNew( VLC_OBJECT(p_input), &p_es->fmt, NULL,
input_priv(p_input)->p_resource,
p_sys->p_sout_record, false,
&decoder_cbs, p_sys );
if( p_es->p_dec_record && p_sys->b_buffering )
input_DecoderStartWait( p_es->p_dec_record );
}
......@@ -1844,8 +1980,10 @@ static void EsOutCreateDecoder( es_out_t *out, es_out_id_t *p_es )
if( !p_es->p_clock )
return;
dec = input_DecoderNew( p_input, &p_es->id, &p_es->fmt, p_es->p_clock,
input_priv(p_input)->p_sout );
input_thread_private_t *priv = input_priv(p_input);
dec = input_DecoderNew( VLC_OBJECT(p_input), &p_es->fmt, p_es->p_clock,
priv->p_resource, priv->p_sout,
priv->b_thumbnailing, &decoder_cbs, p_sys );
if( dec != NULL )
{
input_DecoderChangeRate( dec, p_sys->rate );
......@@ -1855,8 +1993,10 @@ static void EsOutCreateDecoder( es_out_t *out, es_out_id_t *p_es )
if( !p_es->p_master && p_sys->p_sout_record )
{
p_es->p_dec_record = input_DecoderNew( p_input, &p_es->id, &p_es->fmt,
NULL, p_sys->p_sout_record );
p_es->p_dec_record =
input_DecoderNew( VLC_OBJECT(p_input), &p_es->fmt, NULL,
priv->p_resource, p_sys->p_sout_record, false,
&decoder_cbs, p_sys );
if( p_es->p_dec_record && p_sys->b_buffering )
input_DecoderStartWait( p_es->p_dec_record );
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment